/*-------------------------------------------------------------------------
 *
 * parsenodes.h
 *	  解析树节点的定义
 *
 * 许多在解析树中使用的节点类型包括一个 "位置" 字段。
 * 这是原始源文本中的一个字节（而不是字符）偏移，用于在与节点相关的错误发生时
 * 定位错误光标。访问原始源文本是使用位置的必要条件。在最上层（语句）级别，我们还提供
 * 一个语句长度，同样以字节为单位，以方便在多语句源字符串中识别语句边界。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/parsenodes.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PARSENODES_H
#define PARSENODES_H

#include "nodes/bitmapset.h"
#include "nodes/lockoptions.h"
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"


typedef enum OverridingKind
{
	OVERRIDING_NOT_SET = 0,
	OVERRIDING_USER_VALUE,
	OVERRIDING_SYSTEM_VALUE
} OverridingKind;

/* 查询的可能来源 */
typedef enum QuerySource
{
	QSRC_ORIGINAL,				/* 原始解析树（显式查询） */
	QSRC_PARSER,				/* 由解析分析添加（现在未使用） */
	QSRC_INSTEAD_RULE,			/* 由无条件 INSTEAD 规则添加 */
	QSRC_QUAL_INSTEAD_RULE,		/* 由条件 INSTEAD 规则添加 */
	QSRC_NON_INSTEAD_RULE		/* 由非 INSTEAD 规则添加 */
} QuerySource;

/* ORDER BY 和 CREATE INDEX 的排序选项 */
typedef enum SortByDir
{
	SORTBY_DEFAULT,
	SORTBY_ASC,
	SORTBY_DESC,
	SORTBY_USING				/* 在 CREATE INDEX ... 中不允许 */
} SortByDir;

typedef enum SortByNulls
{
	SORTBY_NULLS_DEFAULT,
	SORTBY_NULLS_FIRST,
	SORTBY_NULLS_LAST
} SortByNulls;

/* [ ALL | DISTINCT ] 的选项 */
typedef enum SetQuantifier
{
	SET_QUANTIFIER_DEFAULT,
	SET_QUANTIFIER_ALL,
	SET_QUANTIFIER_DISTINCT
} SetQuantifier;

/*
 * 授予的权限被编码，以便我们可以在位掩码中将它们或运算。
 * 当前的 AclItem 表示限制我们只能有 16 种不同的权限，
 * 尽管 AclMode 被定义为 uint32。 请参见 utils/acl.h。
 *
 * 注意：更改这些代码会破坏存储的 ACL，因此强制 initdb。
 */
typedef uint32 AclMode;			/* 特权位的位掩码 */

#define ACL_INSERT		(1<<0)	/* 对于关系 */
#define ACL_SELECT		(1<<1)
#define ACL_UPDATE		(1<<2)
#define ACL_DELETE		(1<<3)
#define ACL_TRUNCATE	(1<<4)
#define ACL_REFERENCES	(1<<5)
#define ACL_TRIGGER		(1<<6)
#define ACL_EXECUTE		(1<<7)	/* 对于函数 */
#define ACL_USAGE		(1<<8)	/* 对于语言、命名空间、FDWs 和
								 * 服务器 */
#define ACL_CREATE		(1<<9)	/* 对于命名空间和数据库 */
#define ACL_CREATE_TEMP (1<<10) /* 对于数据库 */
#define ACL_CONNECT		(1<<11) /* 对于数据库 */
#define ACL_SET			(1<<12) /* 用于配置参数 */
#define ACL_ALTER_SYSTEM (1<<13)	/* 用于配置参数 */
#define N_ACL_RIGHTS	14		/* 1 加上最后一个 1<<x */
#define ACL_NO_RIGHTS	0
/* 目前，SELECT ... FOR [KEY] UPDATE/SHARE 需要 UPDATE 权限 */
#define ACL_SELECT_FOR_UPDATE	ACL_UPDATE


/*****************************************************************************
 *	查询树
 *****************************************************************************/

/*
 * 查询 -
 *	  解析分析将所有语句转换为查询树
 *	  以供重写器和规划器进一步处理。
 *
 *	  功能语句（即不可优化的语句）将其
 *	  utilityStmt 字段设置，查询的其余部分大部分是虚拟的。
 *
 *	  规划将查询树转换为由 PlannedStmt
 *	  节点引导的计划树 --- 查询结构不被执行器使用。
 */
typedef struct Query
{
	NodeTag		type;

	CmdType		commandType;	/* select|insert|update|delete|merge|utility */

	QuerySource querySource;	/* 我从哪里来？ */

	uint64		queryId;		/* 查询标识符（可以由插件设置） */

	bool		canSetTag;		/* 我是否设置命令结果标签？ */

	Node	   *utilityStmt;	/* 如果 commandType == CMD_UTILITY 则非空 */

	int			resultRelation; /* INSERT/UPDATE/DELETE/MERGE 的目标关系的 rtable 索引；SELECT 的为 0 */

	bool		hasAggs;		/* 在 tlist 中有聚合函数 */
	bool		hasWindowFuncs; /* 在 tlist 中有窗口函数 */
	bool		hasTargetSRFs;	/* 在 tlist 中有返回集函数 */
	bool		hasSubLinks;	/* 有子查询 SubLink */
	bool		hasDistinctOn;	/* distinctClause 来自 DISTINCT ON */
	bool		hasRecursive;	/* 指定了 WITH RECURSIVE */
	bool		hasModifyingCTE;	/* 在 WITH 中有 INSERT/UPDATE/DELETE */
	bool		hasForUpdate;	/* 指定了 FOR [KEY] UPDATE/SHARE */
	bool		hasRowSecurity; /* 重写器已应用某些 RLS 策略 */

	bool		isReturn;		/* 是一个 RETURN 语句 */

	List	   *cteList;		/* WITH 列表（CommonTableExpr 的）*/

	List	   *rtable;			/* 范围表项列表 */
	FromExpr   *jointree;		/* 表连接树（FROM 和 WHERE 子句）;
								 * 也用于 MERGE 的 USING 子句 */

	List	   *mergeActionList;	/* MERGE（仅）操作的动作列表 */
	bool		mergeUseOuterJoin;	/* 是否使用外连接 */

	List	   *targetList;		/* 目标列表（TargetEntry 的） */

	OverridingKind override;	/* OVERRIDING 子句 */

	OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */

	List	   *returningList;	/* 返回值列表（TargetEntry 的） */

	List	   *groupClause;	/* SortGroupClause 的列表 */
	bool		groupDistinct;	/* group by 子句是否唯一？ */

	List	   *groupingSets;	/* 如果存在，GroupingSet 的列表 */

	Node	   *havingQual;		/* 应用于组的资格条件 */

	List	   *windowClause;	/* WindowClause 的列表 */

	List	   *distinctClause; /* SortGroupClause 的列表 */

	List	   *sortClause;		/* SortGroupClause 的列表 */

	Node	   *limitOffset;	/* 要跳过的结果元组数量（int8 表达式） */
	Node	   *limitCount;		/* 要返回的结果元组数量（int8 表达式） */
	LimitOption limitOption;	/* 限制类型 */

	List	   *rowMarks;		/* RowMarkClause 的列表 */

	Node	   *setOperations;	/* 如果这是 UNION/INTERSECT/EXCEPT 查询的顶层，则为集合操作树 */

	List	   *constraintDeps; /* 查询所依赖的 pg_constraint OID 列表，以确保其语义有效 */

	List	   *withCheckOptions;	/* a list of WithCheckOption's (added
									 * during rewrite) */

	/*
	 * 以下两个字段标识包含此查询的源文本字符串部分。它们通常只在顶层查询中填充，而不在子查询中。当未设置时，它们可能都是零，或都是-1，表示“未知”。
	 */
	int			stmt_location;	/* 起始位置，如果未知则为-1 */
	int			stmt_len;		/* 字节长度；0表示“字符串其余部分” */
} Query;


/****************************************************************************
 *	支持解析树的数据结构
 *
 *	这些节点类型大多数出现在语法生成的原始解析树中，并且通过解析器转换为其他形式。它们中的少数以原样形式出现在转换后的查询树中。
 ****************************************************************************/

/*
 * TypeName - 在定义中指定一个类型
 *
 * 对于内部生成的TypeName结构，通常通过OID指定类型比通过名称更容易。如果“names”是NIL，则实际类型OID由typeOid给出，否则typeOid不使用。
 * 同样，如果“typmods”是NIL，则实际的typmod预期在typemod中预先指定，否则typemod不使用。
 *
 * 如果pct_type为真，则names实际上是字段名称，我们查找该字段的类型。 否则（即正常情况），names是一个类型名称，可能带有模式和数据库名称的限定。
 */
typedef struct TypeName
{
	NodeTag		type;
	List	   *names;			/* 限定名称（String节点列表） */
	Oid			typeOid;		/* 由OID标识的类型 */
	bool		setof;			/* 是一个集合吗？ */
	bool		pct_type;		/* %TYPE已指定吗？ */
	List	   *typmods;		/* 类型修饰符表达式 */
	int32		typemod;		/* 预先指定的类型修饰符 */
	List	   *arrayBounds;	/* 数组边界 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} TypeName;

/*
 * ColumnRef - 指定对列的引用，或可能是整个元组
 *
 * “fields”列表必须非空。它可以包含String节点（表示名称）和A_Star节点（表示‘*’的出现）。目前，A_Star只能作为最后一个列表元素出现——语法负责强制执行这一点！
 *
 * 注意：任何容器下标或从复合列中选择字段的操作由ColumnRef上方的A_Indirection节点表示。然而，为了简化，在正常情况下，从表名称的初始字段选择在ColumnRef中表示，而不是通过添加A_Indirection。
 */
typedef struct ColumnRef
{
	NodeTag		type;
	List	   *fields;			/* 字段名称（String节点）或A_Star */
	int			location;		/* 令牌位置，如果未知则为-1 */
} ColumnRef;

/*
 * ParamRef - 指定一个$n参数引用
 */
typedef struct ParamRef
{
	NodeTag		type;
	int			number;			/* 参数的编号 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} ParamRef;

/*
 * A_Expr - 中缀、前缀和后缀表达式
 */
typedef enum A_Expr_Kind
{
	AEXPR_OP,					/* 普通运算符 */
	AEXPR_OP_ANY,				/* 标量操作 ANY（数组） */
	AEXPR_OP_ALL,				/* 标量操作 ALL（数组） */
	AEXPR_DISTINCT,				/* IS DISTINCT FROM - 名称必须是“=” */
	AEXPR_NOT_DISTINCT,			/* IS NOT DISTINCT FROM - 名称必须是“=” */
	AEXPR_NULLIF,				/* NULLIF - 名称必须是“=” */
	AEXPR_IN,					/* [NOT] IN - 名称必须是“=”或“<>” */
	AEXPR_LIKE,					/* [NOT] LIKE - 名称必须是“~~”或“!~~” */
	AEXPR_ILIKE,				/* [NOT] ILIKE - 名称必须是“~~*”或“!~~*” */
	AEXPR_SIMILAR,				/* [NOT] SIMILAR - 名称必须是“~”或“!~” */
	AEXPR_BETWEEN,				/* 名称必须是“BETWEEN” */
	AEXPR_NOT_BETWEEN,			/* 名称必须为 "NOT BETWEEN" */
	AEXPR_BETWEEN_SYM,			/* 名称必须为 "BETWEEN SYMMETRIC" */
	AEXPR_NOT_BETWEEN_SYM		/* 名称必须为 "NOT BETWEEN SYMMETRIC" */
} A_Expr_Kind;

typedef struct A_Expr
{
	NodeTag		type;
	A_Expr_Kind kind;			/* 详见上文 */
	List	   *name;			/* 操作符的可能限定名称 */
	Node	   *lexpr;			/* 左参数，如果没有则为 NULL */
	Node	   *rexpr;			/* 右参数，如果没有则为 NULL */
	int			location;		/* 令牌位置，如果未知则为-1 */
} A_Expr;

/*
 * A_Const - 文本常量
 */
typedef struct A_Const
{
	NodeTag		type;

	/*
	 * 值节点是内联的以提高性能。你可以将 'val' 视为一个节点，
	 * 就像在 IsA(&val, Integer) 中一样。如果 isnull 为真，则 'val' 无效。
	 */
	union ValUnion
	{
		Node		node;
		Integer		ival;
		Float		fval;
		Boolean		boolval;
		String		sval;
		BitString	bsval;
	}			val;
	bool		isnull;			/* SQL NULL 常量 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} A_Const;

/*
 * TypeCast - 一个 CAST 表达式
 */
typedef struct TypeCast
{
	NodeTag		type;
	Node	   *arg;			/* 被转换的表达式 */
	TypeName   *typeName;		/* 目标类型 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} TypeCast;

/*
 * CollateClause - 一个 COLLATE 表达式
 */
typedef struct CollateClause
{
	NodeTag		type;
	Node	   *arg;			/* 输入表达式 */
	List	   *collname;		/* 可能限定的排序名称 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} CollateClause;

/*
 * RoleSpec - 一个角色名称或几个特殊值之一。
 */
typedef enum RoleSpecType
{
	ROLESPEC_CSTRING,			/* 角色名以 C 字符串存储 */
	ROLESPEC_CURRENT_ROLE,		/* 角色规格为 CURRENT_ROLE */
	ROLESPEC_CURRENT_USER,		/* 角色规格为 CURRENT_USER */
	ROLESPEC_SESSION_USER,		/* 角色规格为 SESSION_USER */
	ROLESPEC_PUBLIC				/* 角色名为 "public" */
} RoleSpecType;

typedef struct RoleSpec
{
	NodeTag		type;
	RoleSpecType roletype;		/* 此角色规格的类型 */
	char	   *rolename;		/* 仅对 ROLESPEC_CSTRING 填充 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} RoleSpec;

/*
 * FuncCall - 一个函数或聚合调用
 *
 * agg_order (如果不是 NIL) 表示我们看到了 'foo(... ORDER BY ...)'，或者如果
 * agg_within_group 为真，则表示它是 'foo(...) WITHIN GROUP (ORDER BY ...)'。
 * agg_star 表示我们看到了 'foo(*)' 构造，而 agg_distinct
 * 表示我们看到了 'foo(DISTINCT ...)'。在任何这些情况下，构造 *必须* 是一个聚合调用。
 * 否则，它可能是一个聚合或其他种类的函数。然而，如果存在 FILTER 或 OVER，
 * 它最好是一个聚合或窗口函数。
 *
 * 通常，你会通过 makeFuncCall() 初始化这个，然后再根据需要更改
 * 结构中其默认值不匹配的部分。
 */
typedef struct FuncCall
{
	NodeTag		type;
	List	   *funcname;		/* 函数的限定名称 */
	List	   *args;			/* 参数（表达式列表） */
	List	   *agg_order;		/* ORDER BY（SortBy 列表） */
	Node	   *agg_filter;		/* FILTER 子句（如果有的话） */
	struct WindowDef *over;		/* OVER 子句（如果有的话） */
	bool		agg_within_group;	/* ORDER BY 在 WITHIN GROUP 中出现 */
	bool		agg_star;		/* 参数实际上是 '*' */
	bool		agg_distinct;	/* 参数被标记为 DISTINCT */
	bool		func_variadic;	/* 最后一个参数被标记为 VARIADIC */
	CoercionForm funcformat;	/* 如何显示这个节点 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} FuncCall;

/*
 * A_Star - '*' 表示表或复合字段的所有列
 *
 * 这可以出现在 ColumnRef.fields、A_Indirection.indirection 和
 * ResTarget.indirection 列表中。
 */
typedef struct A_Star
{
	NodeTag		type;
} A_Star;

/*
 * A_Indices - 数组下标或切片边界 ([idx] 或 [lidx:uidx])
 *
 * 在切片的情况下，lidx 和 uidx 中的一个或两个可以为 NULL（省略）。
 * 在非切片的情况下，uidx 保存单个下标，lidx 始终为 NULL。
 */
typedef struct A_Indices
{
	NodeTag		type;
	bool		is_slice;		/* 如果是切片（即，冒号存在）则为真 */
	Node	   *lidx;			/* 切片下界（如果有） */
	Node	   *uidx;			/* 下标，或切片上界（如果有） */
} A_Indices;

/*
 * A_Indirection - 从表达式中选择字段和/或数组元素
 *
 * 间接列表可以包含 A_Indices 节点（表示下标），String 节点（表示字段选择 --- 
 * 字符串值是要选择的字段的名称）和 A_Star 节点（表示选择复合类型的所有字段）。
 * 例如，一个复杂的选择操作如
 *				(foo).field1[42][7].field2
 * 将用具有 4 个元素的间接列表的单个 A_Indirection 节点表示。
 *
 * 目前，A_Star 只能作为最后一个列表元素出现 --- 语法
 * 负责执行这一点！
 */
typedef struct A_Indirection
{
	NodeTag		type;
	Node	   *arg;			/* 被选择的对象 */
	List	   *indirection;	/* 下标和/或字段名称和/或 * */
} A_Indirection;

/*
 * A_ArrayExpr - 一个 ARRAY[] 构造
 */
typedef struct A_ArrayExpr
{
	NodeTag		type;
	List	   *elements;		/* 数组元素表达式 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} A_ArrayExpr;

/*
 * ResTarget -
 *	  结果目标（用于预变换解析树的目标列表）
 *
 * 在 SELECT 目标列表中，“name”是来自“AS ColumnLabel”子句的列标签，或 NULL（如果没有），
 * “val”是值表达式本身。“indirection”字段未使用。
 *
 * INSERT 在其目标列名称列表中使用 ResTarget。在这里，“name”是目标列的名称，
 * “indirection”存储附加到目标的任何下标，而“val”未使用。
 *
 * 在 UPDATE 目标列表中，“name”是目标列的名称，“indirection”存储附加到目标的任何下标，
 * 而“val”是要赋值的表达式。
 *
 * 有关可以出现在“indirection”中的内容的更多信息，请参见 A_Indirection。
 */
typedef struct ResTarget
{
	NodeTag		type;
	char	   *name;			/* 列名称或 NULL */
	List	   *indirection;	/* 下标、字段名称和 '*'，或 NIL */
	Node	   *val;			/* 要计算或分配的值表达式 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} ResTarget;

/*
 * MultiAssignRef - 用于 UPDATE 的一行源表达式的元素
 *
 * 在 UPDATE 目标列表中，当我们有 SET (a,b,c) = 行值表达式时，
 * 我们为每个 a,b,c 生成单独的 ResTarget 项。它们的“val”树
 * 是 MultiAssignRef 节点，编号为 1..n，链接到行值表达式的
 * 公共副本（解析分析将仅在处理 colno=1 的 MultiAssignRef 时处理一次）。
 */
typedef struct MultiAssignRef
{
	NodeTag		type;
	Node	   *source;			/* 行值表达式 */
	int			colno;			/* 该目标的列号（1..n） */
	int			ncolumns;		/* 构造中的目标数量 */
} MultiAssignRef;

/*
 * SortBy - 用于 ORDER BY 子句
 */
typedef struct SortBy
{
	NodeTag		type;
	Node	   *node;			/* 用于排序的表达式 */
	SortByDir	sortby_dir;		/* ASC/DESC/USING/default */
	SortByNulls sortby_nulls;	/* NULLS FIRST/LAST */
	List	   *useOp;			/* 如果 SORTBY_USING，则使用的操作符名称 */
	int			location;		/* 操作符位置，如果没有/未知则为 -1 */
} SortBy;

/*
 * WindowDef - 窗口和 OVER 子句的原始表示
 *
 * 对于窗口列表中的条目，“name”是正在定义的窗口名称。
 * 对于 OVER 子句，我们使用“name”表示“OVER 窗口”语法，或使用“refname”
 * 表示“OVER (window)”语法，这两者有细微的不同——后者
 * 暗示覆盖窗口帧子句。
 */
typedef struct WindowDef
{
	NodeTag		type;
	char	   *name;			/* 窗口自己的名称 */
	char	   *refname;		/* 引用的窗口名称（如果有） */
	List	   *partitionClause;	/* PARTITION BY 表达式列表 */
	List	   *orderClause;	/* ORDER BY（SortBy 列表） */
	int			frameOptions;	/* frame_clause 选项，见下文 */
	Node	   *startOffset;	/* 起始界限的表达式（如果有） */
	Node	   *endOffset;		/* 结束界限的表达式（如果有） */
	int			location;		/* 解析位置，或 -1 如果没有/未知 */
} WindowDef;

/*
 * frameOptions 是这些位的 OR。NONDEFAULT 和 BETWEEN 位被
 * 用于让 ruleutils.c 能够知道哪些属性被指定了
 * 哪些是默认的；无论如何，正确的行为位必须被设置。
 * START_foo 和 END_foo 选项必须成对相邻位出现，以方便 gram.y，
 * 尽管其中一些是无用的/无效的。
 */
#define FRAMEOPTION_NONDEFAULT					0x00001 /* 是否有指定？ */
#define FRAMEOPTION_RANGE						0x00002 /* RANGE 行为 */
#define FRAMEOPTION_ROWS						0x00004 /* ROWS 行为 */
#define FRAMEOPTION_GROUPS						0x00008 /* GROUPS 行为 */
#define FRAMEOPTION_BETWEEN						0x00010 /* 是否给定 BETWEEN？ */
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING	0x00020 /* 开始是 U. P. */
#define FRAMEOPTION_END_UNBOUNDED_PRECEDING		0x00040 /* （不允许） */
#define FRAMEOPTION_START_UNBOUNDED_FOLLOWING	0x00080 /* （不允许） */
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING		0x00100 /* 结束是 U. F. */
#define FRAMEOPTION_START_CURRENT_ROW			0x00200 /* 开始是 C. R. */
#define FRAMEOPTION_END_CURRENT_ROW				0x00400 /* 结束是 C. R. */
#define FRAMEOPTION_START_OFFSET_PRECEDING		0x00800 /* 开始是 O. P. */
#define FRAMEOPTION_END_OFFSET_PRECEDING		0x01000 /* 结束是 O. P. */
#define FRAMEOPTION_START_OFFSET_FOLLOWING		0x02000 /* 开始是 O. F. */
#define FRAMEOPTION_END_OFFSET_FOLLOWING		0x04000 /* 结束是 O. F. */
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW			0x08000 /* 忽略 C.R. */
#define FRAMEOPTION_EXCLUDE_GROUP				0x10000 /* 省略 C.R. 和同类 */
#define FRAMEOPTION_EXCLUDE_TIES				0x20000 /* 省略 C.R. 的同类 */

#define FRAMEOPTION_START_OFFSET \
	(FRAMEOPTION_START_OFFSET_PRECEDING | FRAMEOPTION_START_OFFSET_FOLLOWING)
#define FRAMEOPTION_END_OFFSET \
	(FRAMEOPTION_END_OFFSET_PRECEDING | FRAMEOPTION_END_OFFSET_FOLLOWING)
#define FRAMEOPTION_EXCLUSION \
	(FRAMEOPTION_EXCLUDE_CURRENT_ROW | FRAMEOPTION_EXCLUDE_GROUP | \
	 FRAMEOPTION_EXCLUDE_TIES)

#define FRAMEOPTION_DEFAULTS \
	(FRAMEOPTION_RANGE | FRAMEOPTION_START_UNBOUNDED_PRECEDING | \
	 FRAMEOPTION_END_CURRENT_ROW)

/*
 * RangeSubselect - 出现在 FROM 子句中的子查询
 */
typedef struct RangeSubselect
{
	NodeTag		type;
	bool		lateral;		/* 是否有 LATERAL 前缀？ */
	Node	   *subquery;		/* 未转换的子选择子句 */
	Alias	   *alias;			/* 表别名和可选的列别名 */
} RangeSubselect;

/*
 * RangeFunction - 出现在 FROM 子句中的函数调用
 *
 * functions 是一个列表，因为我们用它来表示构造
 * ROWS FROM(func1(...), func2(...), ...)。这个列表的每个元素是一个
 * 两元素子列表，第一个元素是未转换的函数调用树，
 * 第二个元素是一个可能为空的 ColumnDef
 * 节点列表，表示在 ROWS FROM() 语法中附加到该函数的任何 columndef 列表。
 *
 * alias 和 coldeflist 表示在顶层附加的任何别名和/或 columndef 列表。
 * （我们不允许 coldeflist 在这里和每个函数中同时出现，但这是在解析分析中检查的，而不是通过语法。）
 */
typedef struct RangeFunction
{
	NodeTag		type;
	bool		lateral;		/* 是否有 LATERAL 前缀？ */
	bool		ordinality;		/* 是否有 WITH ORDINALITY 后缀？ */
	bool		is_rowsfrom;	/* 是 ROWS FROM() 语法的结果？ */
	List	   *functions;		/* 每个函数的信息，见上文 */
	Alias	   *alias;			/* 表别名和可选的列别名 */
	List	   *coldeflist;		/* 描述函数返回 RECORD 的结果的 ColumnDef 节点列表 */
} RangeFunction;

/*
 * RangeTableFunc - "表函数" 的原始形式，如 XMLTABLE
 */
typedef struct RangeTableFunc
{
	NodeTag		type;
	bool		lateral;		/* 是否有 LATERAL 前缀？ */
	Node	   *docexpr;		/* 文档表达式 */
	Node	   *rowexpr;		/* 行生成器表达式 */
	List	   *namespaces;		/* 作为 ResTarget 的命名空间列表 */
	List	   *columns;		/* RangeTableFuncCol 的列表 */
	Alias	   *alias;			/* 表别名和可选的列别名 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} RangeTableFunc;

/*
 * RangeTableFuncCol - RangeTableFunc->columns 中的一列
 *
 * 如果 for_ordinality 为 true（FOR ORDINALITY），则该列为 int4
 * 列，其余字段被忽略。
 */
typedef struct RangeTableFuncCol
{
	NodeTag		type;
	char	   *colname;		/* 生成的列的名称 */
	TypeName   *typeName;		/* 生成的列的类型 */
	bool		for_ordinality; /* 是否具有 FOR ORDINALITY？ */
	bool		is_not_null;	/* 是否具有 NOT NULL？ */
	Node	   *colexpr;		/* 列过滤表达式 */
	Node	   *coldefexpr;		/* 列默认值表达式 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} RangeTableFuncCol;

/*
 * RangeTableSample - 出现在原始 FROM 子句中的 TABLESAMPLE
 *
 * 此节点仅在原始解析树中出现，表示
 *		<relation> TABLESAMPLE <method> (<params>) REPEATABLE (<num>)
 * 目前，<relation> 只能是 RangeVar，但我们将来可能允许 RangeSubselect 和其他选项。
 * 请注意，RangeTableSample 包裹在表示 <relation> 的节点周围，而不是作为其子字段。
 */
typedef struct RangeTableSample
{
	NodeTag		type;
	Node	   *relation;		/* 要采样的关系 */
	List	   *method;			/* 采样方法名称（可能带有资格） */
	List	   *args;			/* 采样方法的参数 */
	Node	   *repeatable;		/* REPEATABLE 表达式，或 NULL 如果没有 */
	int			location;		/* 方法名称位置，或者 -1 如果未知 */
} RangeTableSample;

/*
 * ColumnDef - 列定义（用于各种创建）
 *
 * 如果列具有默认值，我们可能在“原始”形式（未经转换的解析树）或“熟化”形式
 * （后解析分析，可执行表达式树）中有值表达式，这取决于该 ColumnDef 节点是如何创建的
 * （通过解析或从现有关系继承）。我们在同一节点中绝不应该同时存在两者！
 *
 * 类似地，我们可能有 COLLATED 规范，原始形式
 * （表示为 arg==NULL 的 CollateClause）或熟化形式
 * （排序的 OID）。
 *
 * 约束列表可能包含 gram.y 生成的原始解析树中的 CONSTR_DEFAULT 项，
 * 但 transformCreateStmt 将删除该项，并设置 raw_default。
 * CONSTR_DEFAULT 项不应出现在任何后续处理。
 */
typedef struct ColumnDef
{
	NodeTag		type;
	char	   *colname;		/* 列的名称 */
	TypeName   *typeName;		/* 列的类型 */
	char	   *compression;	/* 列的压缩方法 */
	int			inhcount;		/* 列被继承的次数 */
	bool		is_local;		/* 列具有本地（非继承）定义 */
	bool		is_not_null;	/* 指定了 NOT NULL 约束？ */
	bool		is_from_type;	/* 列定义来自表类型 */
	char		storage;		/* attstorage 设置，或 0 表示默认 */
	Node	   *raw_default;	/* 默认值（未转换的解析树） */
	Node	   *cooked_default; /* 默认值（转化后的表达式树） */
	char		identity;		/* attidentity 设置 */
	RangeVar   *identitySequence;	/* 用于存储身份序列名称的
									 * ALTER TABLE ... ADD COLUMN */
	char		generated;		/* attgenerated 设置 */
	CollateClause *collClause;	/* 未转化的 COLLATE 规范（如果有的话） */
	Oid			collOid;		/* 排序 OID（如果未设置则为 InvalidOid） */
	List	   *constraints;	/* 对列的其他约束 */
	List	   *fdwoptions;		/* 每列 FDW 选项 */
	int			location;		/* 解析位置，或 -1 如果没有/未知 */
} ColumnDef;

/*
 * TableLikeClause - CREATE TABLE ( ... LIKE ... ) 子句
 */
typedef struct TableLikeClause
{
	NodeTag		type;
	RangeVar   *relation;
	bits32		options;		/* TableLikeOption 标志的或操作 */
	Oid			relationOid;	/* 如果表已被查找，则为其 OID */
} TableLikeClause;

typedef enum TableLikeOption
{
	CREATE_TABLE_LIKE_COMMENTS = 1 << 0,
	CREATE_TABLE_LIKE_COMPRESSION = 1 << 1,
	CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 2,
	CREATE_TABLE_LIKE_DEFAULTS = 1 << 3,
	CREATE_TABLE_LIKE_GENERATED = 1 << 4,
	CREATE_TABLE_LIKE_IDENTITY = 1 << 5,
	CREATE_TABLE_LIKE_INDEXES = 1 << 6,
	CREATE_TABLE_LIKE_STATISTICS = 1 << 7,
	CREATE_TABLE_LIKE_STORAGE = 1 << 8,
	CREATE_TABLE_LIKE_ALL = PG_INT32_MAX
} TableLikeOption;

/*
 * IndexElem - 索引参数（用于 CREATE INDEX 和 ON CONFLICT）
 *
 * 对于普通索引属性，'name' 是要索引的表列的名称，
 * 'expr' 为 NULL。对于索引表达式，'name' 为 NULL，
 * 'expr' 为表达式树。
 */
typedef struct IndexElem
{
	NodeTag		type;
	char	   *name;			/* 要索引的属性名称，或 NULL */
	Node	   *expr;			/* 要索引的表达式，或 NULL */
	char	   *indexcolname;	/* 索引列的名称；NULL = 默认 */
	List	   *collation;		/* 排序名称；NIL = 默认 */
	List	   *opclass;		/* 所需操作类的名称；NIL = 默认 */
	List	   *opclassopts;	/* 特定于操作类的选项，或 NIL */
	SortByDir	ordering;		/* ASC/DESC/默认 */
	SortByNulls nulls_ordering; /* FIRST/LAST/默认 */
} IndexElem;

/*
 * DefElem - 一种通用的“名称 = 值”选项定义
 *
 * 在某些上下文中，名称可以带有限定符。此外，某些 SQL 命令
 * 允许将 SET/ADD/DROP 操作附加到选项设置，因此携带一个字段
 * 也是方便的。（注意：目前，我们的做法是语法仅在相关的语句
 * 中允许命名空间和操作；C 代码可以在其他语句中忽略这些字段。）
 */
typedef enum DefElemAction
{
	DEFELEM_UNSPEC,				/* 未提供操作 */
	DEFELEM_SET,
	DEFELEM_ADD,
	DEFELEM_DROP
} DefElemAction;

typedef struct DefElem
{
	NodeTag		type;
	char	   *defnamespace;	/* 如果未限定名称则为 NULL */
	char	   *defname;
	Node	   *arg;			/* 通常为 Integer、Float、String 或
								 * TypeName */
	DefElemAction defaction;	/* 未指定的操作，或 SET/ADD/DROP */
	int			location;		/* 令牌位置，如果未知则为-1 */
} DefElem;

/*
 * LockingClause - FOR [NO KEY] UPDATE/[KEY] SHARE
 *		选项的原始表示
 *
 * 注意：lockedRels == NIL 表示“查询中的所有关系”。否则它
 * 是一系列 RangeVar 节点。（我们主要使用 RangeVar，因为它携带
 * 位置字段——目前，解析分析坚持在 LockingClause 中使用未限定
 * 名称。）
 */
typedef struct LockingClause
{
	NodeTag		type;
	List	   *lockedRels;		/* FOR [KEY] UPDATE/SHARE 关系 */
	LockClauseStrength strength;
	LockWaitPolicy waitPolicy;	/* NOWAIT 和 SKIP LOCKED */
} LockingClause;

/*
 * XMLSERIALIZE（仅在原始解析树中）
 */
typedef struct XmlSerialize
{
	NodeTag		type;
	XmlOptionType xmloption;	/* DOCUMENT 或 CONTENT */
	Node	   *expr;
	TypeName   *typeName;
	int			location;		/* 令牌位置，如果未知则为-1 */
} XmlSerialize;

/* 分区相关定义 */

/*
 * PartitionElem - 单个分区键的解析时表示
 *
 * expr 可以是原始表达式树或解析分析后的表达式。
 * 不过，我们不在磁盘上存储这些内容。
 */
typedef struct PartitionElem
{
	NodeTag		type;
	char	   *name;			/* 划分的列名，或者 NULL */
	Node	   *expr;			/* 划分的表达式，或者 NULL */
	List	   *collation;		/* 排序名称；NIL = 默认 */
	List	   *opclass;		/* 所需操作类的名称；NIL = 默认 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} PartitionElem;

/*
 * PartitionSpec - 解析时的分区键规范表示
 *
 * 这代表我们将要划分的键空间。
 */
typedef struct PartitionSpec
{
	NodeTag		type;
	char	   *strategy;		/* 划分策略（'hash'，'list'或
								 * 'range'） */
	List	   *partParams;		/* PartitionElems 的列表 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} PartitionSpec;

/* 划分策略的内部代码 */
#define PARTITION_STRATEGY_HASH		'h'
#define PARTITION_STRATEGY_LIST		'l'
#define PARTITION_STRATEGY_RANGE	'r'

/*
 * PartitionBoundSpec - 分区边界规范
 *
 * 这表示分配给特定分区的分区键空间部分。它们存储在 pg_class.relpartbound 中。
 */
struct PartitionBoundSpec
{
	NodeTag		type;

	char		strategy;		/* 参见上述 PARTITION_STRATEGY 代码 */
	bool		is_default;		/* 这是一个默认的分区边界吗？ */

	/* HASH 策略的划分信息： */
	int			modulus;
	int			remainder;

	/* LIST 策略的划分信息： */
	List	   *listdatums;		/* Consts（或原始树中的 A_Consts）列表 */

	/* RANGE 策略的划分信息： */
	List	   *lowerdatums;	/* PartitionRangeDatums 的列表 */
	List	   *upperdatums;	/* PartitionRangeDatums 的列表 */

	int			location;		/* 令牌位置，如果未知则为-1 */
};

/*
 * PartitionRangeDatum - 范围分区边界中的一个值
 *
 * 这可以是 MINVALUE、MAXVALUE 或特定的有界值。
 */
typedef enum PartitionRangeDatumKind
{
	PARTITION_RANGE_DATUM_MINVALUE = -1,	/* 小于任何其他值 */
	PARTITION_RANGE_DATUM_VALUE = 0,	/* 一个特定的（有界）值 */
	PARTITION_RANGE_DATUM_MAXVALUE = 1	/* 大于任何其他值 */
} PartitionRangeDatumKind;

typedef struct PartitionRangeDatum
{
	NodeTag		type;

	PartitionRangeDatumKind kind;
	Node	   *value;			/* Const（或原始树中的 A_Const），如果类型是
								 * PARTITION_RANGE_DATUM_VALUE，否则为 NULL */

	int			location;		/* 令牌位置，如果未知则为-1 */
} PartitionRangeDatum;

/*
 * PartitionCmd - ALTER TABLE/INDEX ATTACH/DETACH PARTITION 命令的信息
 */
typedef struct PartitionCmd
{
	NodeTag		type;
	RangeVar   *name;			/* 要附加/分离的分区名称 */
	PartitionBoundSpec *bound;	/* 对于值，如果正在附加 */
	bool		concurrent;
} PartitionCmd;

/****************************************************************************
 *	查询树的节点
 ****************************************************************************/


/*--------------------
 * RangeTblEntry -
 *	  范围表是一个 RangeTblEntry 节点的列表。
 *
 *	  范围表条目可以表示一个普通关系、FROM 中的子查询，或 JOIN 子句的结果。
 *	  （只有显式的 JOIN 语法产生 RTE，而不是多个 FROM 项所导致的隐式连接。
 *	  这是因为我们只需要 RTE 来处理 SQL 特性，例如外连接和连接输出列别名。）
 *	  还有其他特殊的 RTE 类型，如 RTEKind 所示。
 *
 *	  注意，我们认为 RTE_RELATION 涵盖任何有 pg_class 条目的东西。
 *	  relkind 区分子案例。
 *
 *	  alias 是一个 Alias 节点，表示附加到 FROM 表达式的 AS 别名子句，
 *	  如果没有子句，则为 NULL。
 *
 *	  eref 是表引用名称和列引用名称（真实名称或别名）。注意，系统列（OID 等）不包括
 *	  在列列表中。
 *	  eref->aliasname 是必需存在的，通常应被用于识别 RTE 以便生成错误消息等。
 *
 *	  在 RELATION RTE 中，alias和 eref 中的列名按物理属性编号索引；
 *	  这意味着必须为已删除的列提供列名条目。在构建 RTE 时，我们为
 *	  被删除的列插入空字符串 ("")。然而请注意，存储的规则可能有非空
 *	  列名，针对自规则创建以来被删除的列（而且列名可能因为列重命名而过时）。
 *	  相同的评论适用于 FUNCTION RTE，当函数的返回类型为命名复合类型时。
 *
 *	  在 JOIN RTE 中，alias 和 eref 中的列名与 joinaliasvars 条目是一对一的。
 *	  当 JOI RTE 的输入的列在解析时已知被删除时，将省略这些列。
 *	  然而，再次强调，存储的规则可能包含自规则创建以来已删除列的条目。
 *	  （这仅可能对于在规则中未实际引用的列。）在加载存储规则时，我们将
 *	  任何此类列的 joinaliasvars 项替换为 null 指针。
 *	  （我们不能简单地从 joinaliasvars 列表中删除它们，因为那样会影响
 *	  其余列表中 Vars 的 attnums。）
 *
 *	  inh 对于应该被扩展以包括继承子项的关系引用为真，
 *	  如果 rel 有任何子项。这 *必须* 对于 RTE_RELATION 条目以外的 RTE 为假。
 *
 *	  inFromCl 标记在 FROM 子句中列出的范围变量。
 *	  对于那些在后台添加到查询中的 RTE，则为假，例如规则的 NEW 和 OLD 变量，
 *	  或 UNION 的子查询。此标志在解析期间未使用（除非在 transformLockingClause 中，
 *	  q.v.）；解析器现在使用一个单独的“命名空间”数据结构来
 *	  控制可见性。但它是 ruleutils.c 需要的，以确定
 *	  RTE 是否应在反编译查询中显示。
 *
 *	  requiredPerms 和 checkAsUser 指定在查询启动时要执行的运行时访问权限
 *	  检查。用户必须具备在 requiredPerms 中用 OR 组合的 *所有*
 *	  权限（零表示没有权限检查）。如果 checkAsUser 不是零，
 *	  则使用该用户的访问权限执行权限检查，而不是当前有效用户 ID。
 *	  （这允许规则充当 setuid 网关。）权限检查仅适用于 RELATION RTE。
 *
 *	  对于 SELECT/INSERT/UPDATE 权限，如果用户没有
 *	  表级权限，则仅需在 selectedCols（用于 SELECT）和/或
 *	  insertedCols 和/或 updatedCols 上具有权限（INSERT 带 ON CONFLICT DO UPDATE 可能
 *	  具有所有 3 个）。selectedCols、insertedCols 和 updatedCols 是位图集，
 *	  不能具有负整数成员，因此在将它们存储在这些字段中之前，我们从列号中减去
 *	  FirstLowInvalidHeapAttributeNumber。整个行的 Var 引用由
 *	  设置 InvalidAttrNumber 的位表示。
 *
 *	  updatedCols 还用于其他一些地方，例如，确定
 *	  触发器何时触发，以及在 FDW 中知道它们需要传输哪些更改的列。
 *
 *	  extraUpdatedCols 不再使用或维护；它始终为空。
 *
 *	  securityQuals 是安全屏障资格的列表（布尔表达式），
 *	  要在返回关系中的行之前以列出的顺序进行测试。
 *	  在解析器输出中始终为 NIL。条目由重写器添加以实施安全屏障视图和/或行级安全性。
 *	  请注意，计划程序将每个布尔表达式转换为隐式 AND 的子列表，
 *	  这是其处理资格表达式的常规习惯。
 *--------------------
 */
typedef enum RTEKind
{
	RTE_RELATION,				/* 普通关系引用 */
	RTE_SUBQUERY,				/* FROM 中的子查询 */
	RTE_JOIN,					/* join */
	RTE_FUNCTION,				/* FROM 中的函数 */
	RTE_TABLEFUNC,				
/* TableFunc(.., 列表) */
	RTE_VALUES,					/* VALUES (<表达式列表>), (<表达式列表>), ... */
	RTE_CTE,					/* 公共表表达式 (WITH 列表元素) */
	RTE_NAMEDTUPLESTORE,		/* 元组存储，例如用于 AFTER 触发器 */
	RTE_RESULT					/* RTE 代表一个空的 FROM 子句；这样的 RTE 由规划器添加，在解析或重写期间不存在 */
} RTEKind;

typedef struct RangeTblEntry
{
	NodeTag		type;

	RTEKind		rtekind;		/* 详见上文 */

	/*
	 * XXX 仅适用于某些 rte 种类的字段应合并到
	 * 一个联合中。我还没有这样做，因为差异会影响大量正在积极工作的代码。FIXME 某天。
	 */

	/*
	 * 对于普通关系 RTE 的有效字段（否则为零）：
	 *
	 * 作为一个特例，RTE_NAMEDTUPLESTORE 也可以设置 relid 来指示
	 * tuplestore 的元组格式与引用的关系相同。这允许引用 AFTER 触发器过渡
	 * 表的计划在底层表被修改时失效。
	 *
	 * rellockmode 实际上是 LOCKMODE，但它声明为 int 是为了避免
	 * 必须在这里包含与锁相关的头文件。如果 RTE 是 INSERT/UPDATE/DELETE/MERGE 的目标，则必须为 RowExclusiveLock，
	 * 否则如果 RTE 是 SELECT FOR UPDATE/FOR SHARE 的目标，则为 RowShareLock，
	 * 否则为 AccessShareLock。
	 *
	 * 注意：在某些情况下，规则扩展可能导致 RTE 被标记为
	 * RowExclusiveLock，即使它不是当前查询的目标；如果 DO ALSO 规则
	 * 仅仅扫描了原始目标表，则会发生这种情况。我们将这些 RTE 保留其原始锁模式，以避免获取额外的较低锁。
	 */
	Oid			relid;			/* 关系的 OID */
	char		relkind;		/* 关系类型（参见 pg_class.relkind） */
	int			rellockmode;	/* 查询对关系要求的锁级别 */
	struct TableSampleClause *tablesample;	/* 采样信息，或 NULL */

	/*
	 * 对于子查询 RTE 的有效字段（否则为 NULL）：
	 */
	Query	   *subquery;		/* 子查询 */
	bool		security_barrier;	/* 是否来自 security_barrier 视图？ */

	/*
	 * 对于联接 RTE 的有效字段（否则为 NULL/零）：
	 *
	 * joinaliasvars 是与联接结果的列对应的（通常是）变量的列表。
	 * 引用联接结果第 K 列的别名变量可以被 joinaliasvars 的第 K 个元素替换——
	 * 但为了简化正确反向列出别名的任务，我们直到规划时间才这样做。
	 * 详细而言：joinaliasvars 的一个元素可以是联接的输入关系之一的变量，
	 * 或者是通过隐式转换为联接输出列类型的变量，或包含两个输入列变量（可能被转换）的 COALESCE 表达式。
	 * 超过第一个 joinmergedcols 条目的元素始终只是变量，
	 * 并且在查询的其他地方永远不会被引用（即，联接别名变量仅为合并列生成）。我们保留这些
	 * 条目仅因为它们在 expandRTE() 和类似代码中是必要的。
	 *
	 * 在从存储的规则加载的查询中，非合并的 joinaliasvars 项目可以是空指针，
	 * 它们是（必然不被引用的）在规则生成后被丢弃的列的占位符。
	 * 此外，一旦规划开始，joinaliasvars 项目可以是几乎任何东西，
	 * 这是由于子查询扁平化替换的结果。
	 *
	 * joinleftcols 是左侧联接输入关系的物理列号的整数列表，这些列被包含在联接中；
	 * 同样，joinrighttcols 是右侧联接输入关系的列号。（这些关系是指关联的 JoinExpr 可以确定。）
	 * 如果联接是 USING/NATURAL，则每个列表中的前几个 joinmergedcols 条目标识合并的列。
	 * 合并的列在联接输出中优先出现，然后是左侧输入的其余列，然后是右侧的其余列。
	 *
	 * 注意，输入列在创建存储规则后可能被丢弃，
	 * 如果它们在查询中未被引用（尤其是，合并的列不能被丢弃）；这在
	 * joinleftcols/joinrighttcols 中没有被考虑。
	 */
	JoinType	jointype;		/* 联接类型 */
	int			joinmergedcols; /* 合并的（JOIN USING）列的数量 */
	List	   *joinaliasvars;	/* 别名变量展开列表 */
	List	   *joinleftcols;	/* 左侧输入列号 */
	List	   *joinrightcols;	/* 右侧输入列号 */

	/*
	 * join_using_alias 是直接附加到 JOIN/USING 的别名子句。
	 * 它与下面的别名字段不同，因为它不会隐藏被联接的表的范围变量。
	 */
	Alias	   *join_using_alias;

	/*
	 * 对于函数 RTE 的有效字段（否则为 NIL/零）：
	 *
	 * 当 funcordinality 为 true 时，eref->colnames 列表包括一个指向
	 * 序列列的别名。序列列在其他情况下是隐式的，必须在诸如
	 * expandRTE() 等地方“手动”处理。
	 */
	List	   *functions;		/* RangeTblFunction 节点的列表 */
	bool		funcordinality; /* 这个是 WITH ORDINALITY 调用吗？ */

	
/*
	 * 表达式有效的 TableFunc RTE 字段（否则为 NULL）:
	 */
	TableFunc  *tablefunc;

	/*
	 * 表达式有效的 values RTE 字段（否则为 NIL）:
	 */
	List	   *values_lists;	/* 表达式列表的列表 */

	/*
	 * 表达式有效的 CTE RTE 字段（否则为 NULL/零）:
	 */
	char	   *ctename;		/* WITH 列表项的名称 */
	Index		ctelevelsup;	/* 查询级别的上升数量 */
	bool		self_reference; /* 这是递归自引用吗？ */

	/*
	 * 对于 CTE、VALUES、ENR 和 TableFunc RTEs 有效的字段（否则为 NIL）：
	 *
	 * 我们需要这些字段以便于 CTE RTEs，使得自引用列的类型是明确定义的。
	 * 对于 VALUES RTEs，显式存储这些信息可以避免通过扫描 values_lists 来重新确定信息。
	 * 对于 ENRs，我们在这里显式存储类型（如果提供了 'relid'，可以从目录中获得信息，但我们仍然需要这些
	 * 用于基于 TupleDesc 的 ENRs，所以我们可以始终在这里存储类型信息）。对于 TableFuncs，这些字段与
	 * TableFunc 节点中的数据是冗余的，但将它们保留在这里允许与其他情况共享一些代码。
	 *
	 * 对于仅 ENRs，我们必须考虑被丢弃列的可能性。
	 * 被丢弃的列包含在这些列表中，但在所有三个列表中都将是零（以及在 eref 中的空字符串条目）。
	 * 测试零 coltype 是检测被丢弃列的标准方法。
	 */
	List	   *coltypes;		/* 列类型 OIDs 的 OID 列表 */
	List	   *coltypmods;		/* 列 typmods 的整数列表 */
	List	   *colcollations;	/* 列 collation OIDs 的 OID 列表 */

	/*
	 * 对于 ENR RTEs 有效的字段（否则为 NULL/零）：
	 */
	char	   *enrname;		/* 瞬态命名关系的名称 */
	Cardinality enrtuples;		/* 从调用者估算或实际得出 */

	/*
	 * 所有 RTEs 有效的字段：
	 */
	Alias	   *alias;			/* 用户编写的别名子句（如果有） */
	Alias	   *eref;			/* 扩展引用名称 */
	bool		lateral;		/* 子查询、函数或值是 LATERAL 吗？ */
	bool		inh;			/* 请求继承吗？ */
	bool		inFromCl;		/* 在 FROM 子句中存在吗？ */
	AclMode		requiredPerms;	/* 所需访问权限的位掩码 */
	Oid			checkAsUser;	/* 如果有效，以此角色检查访问 */
	Bitmapset  *selectedCols;	/* 需要 SELECT 权限的列 */
	Bitmapset  *insertedCols;	/* 需要 INSERT 权限的列 */
	Bitmapset  *updatedCols;	/* 需要 UPDATE 权限的列 */
	Bitmapset  *extraUpdatedCols;	/* 被更新的生成列 */
	List	   *securityQuals;	/* 要应用的安全屏障条件（如果有） */
} RangeTblEntry;

/*
 * RangeTblFunction -
 *	  FUNCTION RTE 中一个函数的 RangeTblEntry 子数据。
 *
 * 如果该函数有列定义列表（对于未指定 RECORD 结果是必需的），funccolnames 列出在定义列表中给出的名称，
 * funccoltypes 列出它们声明的列类型，funccoltypmods 列出它们的 typmods，funccolcollations 列出它们的 collation。
 * 否则，这些字段为 NIL。
 *
 * 请注意，我们不会尝试存储返回命名复合类型的函数的结果信息，因为这些可能会随时间变化。
 * 然而，我们确实记住我们认为该类型有多少列（包括被丢弃的列！），
 * 以便能成功忽略在解析查询后添加的任何列。
 */
typedef struct RangeTblFunction
{
	NodeTag		type;

	Node	   *funcexpr;		/* 函数调用的表达式树 */
	int			funccolcount;	/* 它为 RTE 贡献的列数 */
	/* 这些字段记录列定义列表的内容（如果有）： */
	List	   *funccolnames;	/* 列名称（字符串列表） */
	List	   *funccoltypes;	/* 列类型 OIDs 的 OID 列表 */
	List	   *funccoltypmods; /* 列 typmods 的整数列表 */
	List	   *funccolcollations;	/* 列 collation OIDs 的 OID 列表 */
	/* 这是在规划期间设置的，以供执行者使用： */
	Bitmapset  *funcparams;		/* 影响此函数的 PARAM_EXEC 参数 ID */
} RangeTblFunction;

/*
 * TableSampleClause - 在转换后的 FROM 子句中出现的 TABLESAMPLE
 *
 * 与 RangeTableSample 不同，这是相关 RangeTblEntry 的子节点。
 */
typedef struct TableSampleClause
{
	NodeTag		type;
	Oid			tsmhandler;		/* 表的采样处理函数的 OID */
	List	   *args;			/* 表的采样参数表达式 */
	Expr	   *repeatable;		/* REPEATABLE 表达式，或 NULL 如果没有 */
} TableSampleClause;

/*
 * WithCheckOption -
 *		表示在插入/更新可自动更新视图时应用于新元组的 WITH CHECK OPTION 检查，
 *		或者在插入/更新具有 RLS 的关系时应用的 RLS WITH CHECK
 *		策略。
 */
typedef enum WCOKind
{
	WCO_VIEW_CHECK,				/* 可自动更新视图上的 WCO */
	WCO_RLS_INSERT_CHECK,		/* RLS INSERT WITH CHECK 策略 */
	WCO_RLS_UPDATE_CHECK,		/* RLS UPDATE WITH CHECK 策略 */
	WCO_RLS_CONFLICT_CHECK,		/* RLS ON CONFLICT DO UPDATE USING 策略 */
	WCO_RLS_MERGE_UPDATE_CHECK, /* RLS MERGE UPDATE USING 策略 */
	WCO_RLS_MERGE_DELETE_CHECK	/* RLS MERGE DELETE USING 策略 */
} WCOKind;

typedef struct WithCheckOption
{
	NodeTag		type;
	WCOKind		kind;			/* WCO 的类型 */
	char	   *relname;		/* 指定 WCO 的关系名称 */
	char	   *polname;		/* 正在检查的 RLS 策略名称 */
	Node	   *qual;			/* 要检查的约束条件 */
	bool		cascaded;		/* 对于视图的级联 WCO 为真 */
} WithCheckOption;

/*
 * SortGroupClause -
 *		表示 ORDER BY、GROUP BY、PARTITION BY、
 *		DISTINCT、DISTINCT ON 项目
 *
 * 你可能认为 ORDER BY 只关注定义排序，
 * 而 GROUP/DISTINCT 只关注定义相等性。然而，
 * 实现分组的一种方法是先排序，然后应用类似“uniq”的
 * 过滤器。因此，跟踪 GROUP/DISTINCT 的可能排序操作符也是有趣的，
 * 特别是尝试以将在分组的同时满足请求的 ORDER BY 排序的方式进行排序。
 * 因此我们需要能够比较 ORDER BY 和 GROUP/DISTINCT 列表，这促使
 * 决定赋予它们相同的表示形式。
 *
 * tleSortGroupRef 必须与查询目标列表的恰好一个条目的 ressortgroupref 匹配；
 * 那就是要排序或分组的表达式。
 * eqop 是相等操作符的 OID。
 * sortop 是排序操作符的 OID（一个 "<" 或 ">" 操作符），
 *		如果不可用则为 InvalidOid。
 * nulls_first 代表你所期望的内容。如果 sortop 是 InvalidOid，
 *		那么 nulls_first 就没有意义，应该设置为 false。
 * hashable 为真如果 eqop 是可哈希的（注意这个条件也依赖于
 *		输入表达式的数据类型）。
 *
 * 在 ORDER BY 项目中，所有字段必须有效。（eqop 在此并不是必需的，
 * 但与 sortop 一起获取是便宜的，要求它有效可以简化与分组项的比较。）
 * 请注意，这实际上不足以确定排序：如果 sortop 对排序敏感，
 * 还需要一个排序 OID。我们不在 SortGroupClause 中存储排序，
 * 因为在解析器构建 SortGroupClause 时不可用；相反，查阅引用目标列表表达式的
 * 显式排序以找出它是什么。
 *
 * 在分组项中，eqop 必须有效。如果 eqop 是 btree 相等操作符，
 * 则 sortop 应该设置为一个兼容的排序操作符。
 * 我们倾向于将 eqop/sortop/nulls_first 设置为与查询为
 * 相同 tlist 项呈现的任何 ORDER BY 项匹配。如果没有，我们就
 * 会使用该数据类型的默认排序操作符。
 *
 * 如果 tlist 项的类型有哈希操作类但没有 btree 操作类，
 * 则我们将 eqop 设置为哈希相等操作符，sortop 设置为 InvalidOid，
 * 并将 nulls_first 设置为 false。这种类型的分组项只能通过哈希实现，
 * 当然，它永远不会与 ORDER BY 项匹配。
 *
 * hashable 标志是提供的，因为在构建 SortGroupClause 时
 * 我们通常具有所需的信息，并且稍后再次获取这些信息的成本相对较高。
 * 请注意，不需要“可排序”标志，因为 OidIsValid(sortop) 可以满足目的。
 *
 * 查询可能同时具有 ORDER BY 和 DISTINCT（或 DISTINCT ON）子句。
 * 在 SELECT DISTINCT 中，distinctClause 列表的长度与
 * sortClause 列表相同或更长，而在 SELECT DISTINCT ON 中，通常较短。
 * 这两个列表必须匹配到较短列表的末尾——解析器如有必要会重新排列
 * distinctClause 以使这成立。（这一限制确保只需一个排序步骤即可
 * 同时满足 ORDER BY 和设置 Unique 步骤。这在语义上对于 DISTINCT ON 是必要的，
 * 对于 DISTINCT 则没有真正的缺点。）
 */
typedef struct SortGroupClause
{
	NodeTag		type;
	Index		tleSortGroupRef;	/* 指向目标列表的引用 */
	Oid			eqop;			/* 相等操作符 ('=' 操作) */
	Oid			sortop;			/* 排序操作符 ('<' 操作)，或 0 */
	bool		nulls_first;	/* NULL 值是否在正常值之前？ */
	bool		hashable;		/* eqop 是否可以通过哈希实现？ */
} SortGroupClause;

/*
 * GroupingSet -
 *		表示 CUBE，ROLLUP 和 GROUPING SETS 子句
 *
 * 在具有分组集的查询中，groupClause 包含每个不同表达式的 SortGroupClause 节点的平面列表。实际的 GROUP BY 子句的结构由 groupingSets 树提供。
 *
 * 在原始解析器输出中，GroupingSet 节点（除 SIMPLE 外的所有类型，SIMPLE 未使用）可能与 SelectStmt 的 groupClause 中的表达式混合。 （表达式不能包含 GroupingSet，但列表可能混合 GroupingSet 和表达式节点。）在这一阶段，每个节点的内容是一些可能是 RowExpr 的表达式列表，它代表子列表而不是实际的行构造器，以及在语法上合法的嵌套 GroupingSet 节点。该结构直接反映查询语言。
 *
 * 在解析分析中，转换后的表达式用于构建 tlist 和 SortGroupClause 节点的 groupClause 列表，最终 groupingSets 树被简化为固定格式：
 *
 * EMPTY 节点表示（），显然没有内容
 *
 * SIMPLE 节点表示一个或多个表达式的列表，将被封闭结构视为原子；内容是一个整数列表的 ressortgroupref 值（见 SortGroupClause）
 *
 * CUBE 和 ROLLUP 节点包含一个或多个 SIMPLE 节点的列表。
 *
 * SETS 节点包含一个 EMPTY、SIMPLE、CUBE 或 ROLLUP 节点的列表，但在解析分析后，它们不能包含更多的 SETS 节点；已经应用了足够的语法变换，以至于我们不再有任意深度的嵌套（尽管我们仍然保留了 cube/rollup 的使用）。
 *
 * 注意，如果 groupingSets 树不包含 SIMPLE 节点（叶子处仅有 EMPTY 节点），则 groupClause 将为空，但这仍然是一个聚合查询（类似于在没有 GROUP BY 的情况下使用 aggs 或 HAVING）。
 *
 * 作为一个示例，以下子句：
 *
 * GROUP BY GROUPING SETS ((a,b), CUBE(c,(d,e)))
 *
 * 在原始解析后看起来像这样：
 *
 * SETS( RowExpr(a,b) , CUBE( c, RowExpr(d,e) ) )
 *
 * 并且解析分析将其转换为：
 *
 * SETS( SIMPLE(1,2), CUBE( SIMPLE(3), SIMPLE(4,5) ) )
 */
typedef enum GroupingSetKind
{
	GROUPING_SET_EMPTY,
	GROUPING_SET_SIMPLE,
	GROUPING_SET_ROLLUP,
	GROUPING_SET_CUBE,
	GROUPING_SET_SETS
} GroupingSetKind;

typedef struct GroupingSet
{
	NodeTag		type;
	GroupingSetKind kind;
	List	   *content;
	int			location;
} GroupingSet;

/*
 * WindowClause -
 *		窗口和 OVER 子句的转换表示
 *
 * 解析查询的 windowClause 列表包含这些结构。 "name" 如果子句最初来自 WINDOW，则设置，如果最初是 OVER 子句，则为 NULL（但请注意，我们会合并重复的 OVER）。
 * partitionClause 和 orderClause 是 SortGroupClause 结构的列表。
 * 如果我们有带有 PRECEDING/FOLLOWING 的 RANGE，则该语义由 startInRangeFunc/inRangeColl/inRangeAsc/inRangeNullsFirst 指定起始偏移，或者为 endInRangeFunc/inRange* 指定结束偏移。
 * winref 是 WindowFunc 节点引用的 ID 号；它在查询的 windowClause 列表中必须是唯一的。
 * 当 refname 不是 null 时，partitionClause 始终从那里复制；orderClause 可能会被复制，也可能不会（见 copiedOrder）；根据规范，框架选项从不被复制。
 */
typedef struct WindowClause
{
	NodeTag		type;
	char	   *name;			/* 窗口名称（在 OVER 子句中为 NULL） */
	char	   *refname;		/* 引用的窗口名称（如果有） */
	List	   *partitionClause;	/* PARTITION BY list */
	List	   *orderClause;	/* ORDER BY list */
	int			frameOptions;	/* frame_clause选项，参见WindowDef */
	Node	   *startOffset;	/* 起始界限的表达式（如果有） */
	Node	   *endOffset;		/* 结束界限的表达式（如果有） */
	List	   *runCondition;	/* qual 以帮助短路执行 */
	Oid			startInRangeFunc;	/* startOffset的in_range函数 */
	Oid			endInRangeFunc; /* endOffset的in_range函数 */
	Oid			inRangeColl;	/* in_range测试的排序规则 */
	bool		inRangeAsc;		/* 使用 ASC 排序顺序进行范围测试？ */
	bool		inRangeNullsFirst;	/* 空值在范围测试中优先排序吗？ */
	Index		winref;			/* 窗口函数引用的 ID */
	bool		copiedOrder;	/* 我们是否从 refname 复制了 orderClause？ */
} WindowClause;

/*
 * RowMarkClause -
 *	   FOR [KEY] UPDATE/SHARE 子句的解析器输出表示
 *
 * Query.rowMarks 为每个被识别为 FOR [KEY] UPDATE/SHARE 目标的关系
 * 包含一个单独的 RowMarkClause 节点。如果这些子句之一
 * 应用于子查询，我们会为子查询中的所有普通和
 * 子查询关系生成 RowMarkClauses，但它们被标记为 pushedDown = true 以
 * 区分它们与在当前查询级别显式编写的子句。此外，Query.hasForUpdate 指示
 * 当前查询级别是否存在显式的 FOR UPDATE/SHARE/KEY SHARE 子句。
 */
typedef struct RowMarkClause
{
	NodeTag		type;
	Index		rti;			/* 目标关系的范围表索引 */
	LockClauseStrength strength;
	LockWaitPolicy waitPolicy;	/* NOWAIT 和 SKIP LOCKED */
	bool		pushedDown;		/* 是否从更高的查询级别向下推送？ */
} RowMarkClause;

/*
 * WithClause -
 *	   WITH 子句的表示
 *
 * 注意：WithClause 不会传播到 Query 表示中；
 * 但 CommonTableExpr 会。
 */
typedef struct WithClause
{
	NodeTag		type;
	List	   *ctes;			/* CommonTableExprs 列表 */
	bool		recursive;		/* true = WITH RECURSIVE */
	int			location;		/* 令牌位置，如果未知则为-1 */
} WithClause;

/*
 * InferClause -
 *		ON CONFLICT 唯一索引推断子句
 *
 * 注意：InferClause 不会传播到 Query 表示中。
 */
typedef struct InferClause
{
	NodeTag		type;
	List	   *indexElems;		/* 用于推断唯一索引的 IndexElems */
	Node	   *whereClause;	/* 限制条件（部分索引谓词） */
	char	   *conname;		/* 约束名称，或 NULL 如果没有命名 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} InferClause;

/*
 * OnConflictClause -
 *		ON CONFLICT 子句的表示
 *
 * 注意：OnConflictClause 不会传播到 Query 表示中。
 */
typedef struct OnConflictClause
{
	NodeTag		type;
	OnConflictAction action;	/* DO NOTHING 或 UPDATE？ */
	InferClause *infer;			/* 可选的索引推断子句 */
	List	   *targetList;		/* 目标列表（ResTarget 的） */
	Node	   *whereClause;	/* 限定条件 */
	int			location;		/* 令牌位置，如果未知则为-1 */
} OnConflictClause;

/*
 * CommonTableExpr -
 *	   WITH 列表元素的表示
 */

typedef enum CTEMaterialize
{
	CTEMaterializeDefault,		/* 没有指定选项 */
	CTEMaterializeAlways,		/* MATERIALIZED */
	CTEMaterializeNever			/* NOT MATERIALIZED */
} CTEMaterialize;

typedef struct CTESearchClause
{
	NodeTag		type;
	List	   *search_col_list;
	bool		search_breadth_first;
	char	   *search_seq_column;
	int			location;
} CTESearchClause;

typedef struct CTECycleClause
{
	NodeTag		type;
	List	   *cycle_col_list;
	char	   *cycle_mark_column;
	Node	   *cycle_mark_value;
	Node	   *cycle_mark_default;
	char	   *cycle_path_column;
	int			location;
	/* 这些字段在解析分析期间设置： */
	Oid			cycle_mark_type;	/* _value 和 _default 的通用类型 */
	int			cycle_mark_typmod;
	Oid			cycle_mark_collation;
	Oid			cycle_mark_neop;	/* 类型的 <> 运算符 */
} CTECycleClause;

typedef struct CommonTableExpr
{
	NodeTag		type;
	char	   *ctename;		/* 查询名称（从不限定） */
	List	   *aliascolnames;	/* 可选的列名称列表 */
	CTEMaterialize ctematerialized; /* 这是一个优化围栏吗？ */
	/* SelectStmt/InsertStmt/etc 在解析分析前，Query 之后： */
	Node	   *ctequery;		/* CTE 的子查询 */
	CTESearchClause *search_clause;
	CTECycleClause *cycle_clause;
	int			location;		/* 令牌位置，如果未知则为-1 */
	/* 这些字段在解析分析期间设置： */
	bool		cterecursive;	/* 这个 CTE 实际上是递归的吗？ */
	int			cterefcount;	/* 引用此 CTE 的 RTE 数量
								 * （不包括内部自引用） */
	List	   *ctecolnames;	/* 输出列名称列表 */
	List	   *ctecoltypes;	/* 输出列类型 OID 的 OID 列表 */
	List	   *ctecoltypmods;	/* 输出列类型修饰符的整数列表 */
	List	   *ctecolcollations;	/* 列 collation OIDs 的 OID 列表 */
} CommonTableExpr;

/* 便利宏，用于获取CTE查询的输出tlist */
#define GetCTETargetList(cte) \
	(AssertMacro(IsA((cte)->ctequery, Query)), \
	 ((Query *) (cte)->ctequery)->commandType == CMD_SELECT ? \
	 ((Query *) (cte)->ctequery)->targetList : \
	 ((Query *) (cte)->ctequery)->returningList)

/*
 * MergeWhenClause -
 *		MERGE语句中WHEN子句的原始解析表示
 *
 * 这被转换为MergeAction通过解析分析
 */
typedef struct MergeWhenClause
{
	NodeTag		type;
	bool		matched;		/* true=MATCHED, false=NOT MATCHED */
	CmdType		commandType;	/* INSERT/UPDATE/DELETE/DO NOTHING */
	OverridingKind override;	/* OVERRIDING 子句 */
	Node	   *condition;		/* WHEN conditions (raw parser) */
	List	   *targetList;		/* INSERT/UPDATE targetlist */
	/* 以下成员仅在 INSERT 操作中使用 */
	List	   *values;			/* 要插入的 VALUES，或 NULL */
} MergeWhenClause;

/*
 * MergeAction -
 *		合并语句中 WHEN 子句的转换表示
 */
typedef struct MergeAction
{
	NodeTag		type;
	bool		matched;		/* true=MATCHED, false=NOT MATCHED */
	CmdType		commandType;	/* INSERT/UPDATE/DELETE/DO NOTHING */
	OverridingKind override;	/* OVERRIDING 子句 */
	Node	   *qual;			/* 转换的 WHEN 条件 */
	List	   *targetList;		/* 目标列表 (TargetEntry 的) */
	List	   *updateColnos;	/* 更新的目标属性编号 */
} MergeAction;

/*
 * TriggerTransition -
 *	   过渡行或表命名子句的表示
 *
 * 语法中仅最初支持过渡表，并且仅适用于 AFTER 触发器，但解析器接受其他排列，因此我们可以
 * 从 C 代码中提供有意义的信息。
 */
typedef struct TriggerTransition
{
	NodeTag		type;
	char	   *name;
	bool		isNew;
	bool		isTable;
} TriggerTransition;

/*****************************************************************************
 *		原始语法输出语句
 *****************************************************************************/

/*
 *		RawStmt --- 任何一个语句的原始解析树的容器
 *
 * 解析分析将以 RawStmt 节点为首的原始解析树转换为以 Query 节点为首的已分析语句。对于可优化的语句，
 * 转换是复杂的。对于实用语句，解析器通常只将原始解析树（不包含 RawStmt）转移到
 * Query 节点的 utilityStmt 字段，并且所有有用的工作在执行时进行。
 *
 * stmt_location/stmt_len 标识包含此原始语句的源文本字符串部分（对多语句字符串有用）。
 */
typedef struct RawStmt
{
	NodeTag		type;
	Node	   *stmt;			/* 原始解析树 */
	int			stmt_location;	/* 起始位置，如果未知则为-1 */
	int			stmt_len;		/* 字节长度；0表示“字符串其余部分” */
} RawStmt;

/*****************************************************************************
 *		可优化语句
 *****************************************************************************/

/* ----------------------
 *		插入语句
 *
 * 源表达式由 SelectStmt 表示，适用于 SELECT 和 VALUES 两种情况。如果 selectStmt 为 NULL，
 * 则查询为 INSERT ... DEFAULT VALUES。
 * ----------------------
 */
typedef struct InsertStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要插入的关系 */
	List	   *cols;			/* 可选：目标列的名称 */
	Node	   *selectStmt;		/* 源 SELECT/VALUES，或 NULL */
	OnConflictClause *onConflictClause; /* ON CONFLICT 子句 */
	List	   *returningList;	/* 要返回的表达式列表 */
	WithClause *withClause;		/* WITH 子句 */
	OverridingKind override;	/* OVERRIDING 子句 */
} InsertStmt;

/* ----------------------
 *		删除语句
 * ----------------------
 */
typedef struct DeleteStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要删除的关系 */
	List	   *usingClause;	/* 可选的使用子句，适用于更多表 */
	Node	   *whereClause;	/* 限定条件 */
	List	   *returningList;	/* 要返回的表达式列表 */
	WithClause *withClause;		/* WITH 子句 */
} DeleteStmt;

/* ----------------------
 *		更新语句
 * ----------------------
 */
typedef struct UpdateStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要更新的关系 */
	List	   *targetList;		/* 目标列表（ResTarget 的） */
	Node	   *whereClause;	/* 限定条件 */
	List	   *fromClause;		/* 可选的 from 子句，适用于更多表 */
	List	   *returningList;	/* 要返回的表达式列表 */
	WithClause *withClause;		/* WITH 子句 */
} UpdateStmt;

/* ----------------------
 *		合并语句
 * ----------------------
 */
typedef struct MergeStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要合并到的目标关系 */
	Node	   *sourceRelation; /* 源关系 */
	Node	   *joinCondition;	/* 源和目标之间的联接条件 */
	List	   *mergeWhenClauses;	/* list of MergeWhenClause(es) */
	WithClause *withClause;		/* WITH 子句 */
} MergeStmt;

/* ----------------------
 *		选择语句
 *
 * 一个 "简单的" SELECT 在 gram.y 的输出中由一个单独的 SelectStmt 节点表示；VALUES 构造也是如此。包含集合运算符（UNION, INTERSECT, EXCEPT）的查询由 SelectStmt 节点的树表示，其中叶节点是组件 SELECT，内部节点代表 UNION、INTERSECT 或 EXCEPT 操作符。对于叶节点和内部节点使用相同的节点类型，允许 gram.y 将 ORDER BY、LIMIT 等子句值嵌入 SELECT 语句中，而无需担心它是简单还是复合 SELECT。
 * ----------------------
 */
typedef enum SetOperation
{
	SETOP_NONE = 0,
	SETOP_UNION,
	SETOP_INTERSECT,
	SETOP_EXCEPT
} SetOperation;

typedef struct SelectStmt
{
	NodeTag		type;

	/*
	 * 这些字段仅在 "叶" SelectStmts 中使用。
	 */
	List	   *distinctClause; /* NULL，DISTINCT ON 表达式的列表，或
								 * lcons(NIL,NIL) 表示所有（SELECT DISTINCT） */
	IntoClause *intoClause;		/* SELECT INTO 的目标 */
	List	   *targetList;		/* 目标列表（ResTarget 的） */
	List	   *fromClause;		/* FROM 子句 */
	Node	   *whereClause;	/* WHERE 限定条件 */
	List	   *groupClause;	/* GROUP BY 子句 */
	bool		groupDistinct;	/* 这是 GROUP BY DISTINCT 吗？ */
	Node	   *havingClause;	/* HAVING 条件表达式 */
	List	   *windowClause;	/* WINDOW window_name AS (...), ... */

	/*
	 * 在表示 VALUES 列表的 "叶" 节点中，上述字段均为空，而此字段被设置。请注意，子列表的元素只是表达式，没有 ResTarget 装饰。还要注意，列表元素可以是 DEFAULT（表示为 SetToDefault 节点），无论 VALUES 列表的上下文如何。分析解析是否有效由解析分析来决定。
	 */
	List	   *valuesLists;	/* 未转化的表达式列表 */

	/*
	 * 这些字段在 "叶" SelectStmts 和上层 SelectStmts 中都使用。
	 */
	List	   *sortClause;		/* 排序子句（SortBy 的列表） */
	Node	   *limitOffset;	/* 跳过的结果元组数量 */
	Node	   *limitCount;		/* 返回的结果元组数量 */
	LimitOption limitOption;	/* 限制类型 */
	List	   *lockingClause;	/* FOR UPDATE（LockingClause 的列表） */
	WithClause *withClause;		/* WITH 子句 */

	/*
	 * 这些字段仅在上层 SelectStmts 中使用。
	 */
	SetOperation op;			/* 集合操作的类型 */
	bool		all;			/* 是否指定 ALL？ */
	struct SelectStmt *larg;	/* 左子节点 */
	struct SelectStmt *rarg;	/* 右子节点 */
	/* 最终在此处添加 CORRESPONDING 规格的字段 */
} SelectStmt;


/* ----------------------
 *		后分析查询树的集合操作节点
 *
 * 在解析分析后，带有集合操作的 SELECT 由一个顶级 Query 节点表示，其范围表中包含叶 SELECT 作为子查询。它的 setOperations 字段显示集合操作的树，叶 SelectStmt 节点替换为 RangeTblRef 节点，内部节点替换为 SetOperationStmt 节点。输出列类型的信息也会被添加。（注意子节点不一定直接生成这些类型，但我们已经检查过它们的输出类型可以被强制转换为输出列类型。）此外，如果不是 UNION ALL，则以 SortGroupClause 列的形式提供类型的排序/分组语义信息（与如 DISTINCT 相同的表示方式）。已提供解析后的公共列排序规则；但请注意，如果不是 UNION ALL，则某列可以没有公共排序规则，因此 colCollations 列的成员可以是 InvalidOid，即使该列具有可排序类型。
 * ----------------------
 */
typedef struct SetOperationStmt
{
	NodeTag		type;
	SetOperation op;			/* 集合操作的类型 */
	bool		all;			/* 是否指定 ALL？ */
	Node	   *larg;			/* 左子节点 */
	Node	   *rarg;			/* 右子节点 */
	/* 最终在此处添加 CORRESPONDING 规格的字段 */

	/* 在解析分析过程中派生的字段： */
	List	   *colTypes;		/* 输出列类型 OID 的 OID 列表 */
	List	   *colTypmods;		/* 输出列类型修饰符的整数列表 */
	List	   *colCollations;	/* 输出列排序规则 OID 的 OID 列表 */
	List	   *groupClauses;	/* SortGroupClause 的列表 */
	/* groupClauses 如果是 UNION ALL 则为 NIL，但必须在其他情况下设置 */
} SetOperationStmt;


/*
 * RETURN 语句（在 SQL 函数体内）
 */
typedef struct ReturnStmt
{
	NodeTag		type;
	Node	   *returnval;
} ReturnStmt;


/* ----------------------
 *		PL/pgSQL 赋值语句
 *
 * 与 SelectStmt 一样，这被转换为一个 SELECT 查询。
 * 然而，结果的目标列表更像是一个 UPDATE。
 * ----------------------
 */
typedef struct PLAssignStmt
{
	NodeTag		type;

	char	   *name;			/* 初始列名 */
	List	   *indirection;	/* 下标和字段名（如果有的话） */
	int			nnames;			/* 用于ColumnRef的名称数量 */
	SelectStmt *val;			/* 要赋值的PL/pgSQL表达式 */
	int			location;		/* 名称的令牌位置，或-1如果未知 */
} PLAssignStmt;


/*****************************************************************************
 *		其他语句（不需要优化）
 *
 *		这些不被parser/analyze.c处理，除了将它们放入
 *		Query的utilityStmt字段中。最终这将传递给
 *		ProcessUtility（绕过重写和计划）。某些
 *		语句确实需要解析分析的注意，这是通过
 *		parser/parse_utilcmd.c中的例程在ProcessUtility
 *		接收命令执行后完成的。
 *		DECLARE CURSOR、EXPLAIN和CREATE TABLE AS是特殊情况：
 *		它们包含可优化的语句，通常由
 *		parser/analyze.c正常处理。
 *****************************************************************************/

/*
 * 当一个命令可以作用于几种类型的对象而只需要一个
 * 解析结构时，使用这些常量来指定
 * 对象类型。请注意，命令通常不支持所有类型。
 */

typedef enum ObjectType
{
	OBJECT_ACCESS_METHOD,
	OBJECT_AGGREGATE,
	OBJECT_AMOP,
	OBJECT_AMPROC,
	OBJECT_ATTRIBUTE,			/* 类型的属性，当与列不同 */
	OBJECT_CAST,
	OBJECT_COLUMN,
	OBJECT_COLLATION,
	OBJECT_CONVERSION,
	OBJECT_DATABASE,
	OBJECT_DEFAULT,
	OBJECT_DEFACL,
	OBJECT_DOMAIN,
	OBJECT_DOMCONSTRAINT,
	OBJECT_EVENT_TRIGGER,
	OBJECT_EXTENSION,
	OBJECT_FDW,
	OBJECT_FOREIGN_SERVER,
	OBJECT_FOREIGN_TABLE,
	OBJECT_FUNCTION,
	OBJECT_INDEX,
	OBJECT_LANGUAGE,
	OBJECT_LARGEOBJECT,
	OBJECT_MATVIEW,
	OBJECT_OPCLASS,
	OBJECT_OPERATOR,
	OBJECT_OPFAMILY,
	OBJECT_PARAMETER_ACL,
	OBJECT_POLICY,
	OBJECT_PROCEDURE,
	OBJECT_PUBLICATION,
	OBJECT_PUBLICATION_NAMESPACE,
	OBJECT_PUBLICATION_REL,
	OBJECT_ROLE,
	OBJECT_ROUTINE,
	OBJECT_RULE,
	OBJECT_SCHEMA,
	OBJECT_SEQUENCE,
	OBJECT_SUBSCRIPTION,
	OBJECT_STATISTIC_EXT,
	OBJECT_TABCONSTRAINT,
	OBJECT_TABLE,
	OBJECT_TABLESPACE,
	OBJECT_TRANSFORM,
	OBJECT_TRIGGER,
	OBJECT_TSCONFIGURATION,
	OBJECT_TSDICTIONARY,
	OBJECT_TSPARSER,
	OBJECT_TSTEMPLATE,
	OBJECT_TYPE,
	OBJECT_USER_MAPPING,
	OBJECT_VIEW
} ObjectType;

/* ----------------------
 *		创建模式语句
 *
 * 注意：schemaElts列表包含模式的组件语句
 * 的原始解析树，如CREATE TABLE、GRANT等。它们在
 * 创建模式本身后被分析和执行。
 * ----------------------
 */
typedef struct CreateSchemaStmt
{
	NodeTag		type;
	char	   *schemaname;		/* 要创建的模式的名称 */
	RoleSpec   *authrole;		/* 创建的模式的所有者 */
	List	   *schemaElts;		/* 模式组件（解析节点列表） */
	bool		if_not_exists;	/* 如果模式已经存在就什么也不做？ */
} CreateSchemaStmt;

typedef enum DropBehavior
{
	DROP_RESTRICT,				/* 如果有任何依赖对象则删除失败 */
	DROP_CASCADE				/* 也移除依赖对象 */
} DropBehavior;

/* ----------------------
 *	修改表
 * ----------------------
 */
typedef struct AlterTableStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要操作的表 */
	List	   *cmds;			/* 子命令列表 */
	ObjectType	objtype;		/* 对象类型 */
	bool		missing_ok;		/* 如果表缺失则跳过错误 */
} AlterTableStmt;

typedef enum AlterTableType
{
	AT_AddColumn,				/* 添加列 */
	AT_AddColumnRecurse,		/* 命令/tablecmds.c内部 */
	AT_AddColumnToView,			/* 隐式通过CREATE OR REPLACE VIEW */
	AT_ColumnDefault,			/* 修改列默认值 */
	AT_CookedColumnDefault,		/* 添加一个预设的列默认值 */
	AT_DropNotNull,				/* 修改列删除非空约束 */
	AT_SetNotNull,				/* 修改列设置非空约束 */
	AT_DropExpression,			/* 修改列删除表达式 */
	AT_CheckNotNull,			/* 检查列是否已经标记为非空 */
	AT_SetStatistics,			/* 修改列设置统计信息 */
	AT_SetOptions,				/* 更改列设置 ( 选项 ) */
	AT_ResetOptions,			/* 重置列 ( 选项 ) */
	AT_SetStorage,				/* 设置列存储 */
	AT_SetCompression,			/* 设置列压缩 */
	AT_DropColumn,				/* 删除列 */
	AT_DropColumnRecurse,		/* 命令/tablecmds.c内部 */
	AT_AddIndex,				/* 添加索引 */
	AT_ReAddIndex,				/* 命令/tablecmds.c内部 */
	AT_AddConstraint,			/* 添加约束 */
	AT_AddConstraintRecurse,	/* 命令/tablecmds.c内部 */
	AT_ReAddConstraint,			/* 命令/tablecmds.c内部 */
	AT_ReAddDomainConstraint,	/* 命令/tablecmds.c内部 */
	AT_AlterConstraint,			/* 更改约束 */
	AT_ValidateConstraint,		/* 验证约束 */
	AT_ValidateConstraintRecurse,	/* 命令/tablecmds.c内部 */
	AT_AddIndexConstraint,		/* 使用现有索引添加约束 */
	AT_DropConstraint,			/* 删除约束 */
	AT_DropConstraintRecurse,	/* 命令/tablecmds.c内部 */
	AT_ReAddComment,			/* 命令/tablecmds.c内部 */
	AT_AlterColumnType,			/* 更改列类型 */
	AT_AlterColumnGenericOptions,	/* 更改列选项 (...) */
	AT_ChangeOwner,				/* 更改所有者 */
	AT_ClusterOn,				/* CLUSTER ON */
	AT_DropCluster,				/* SET WITHOUT CLUSTER */
	AT_SetLogged,				/* SET LOGGED */
	AT_SetUnLogged,				/* SET UNLOGGED */
	AT_DropOids,				/* SET WITHOUT OIDS */
	AT_SetAccessMethod,			/* SET ACCESS METHOD */
	AT_SetTableSpace,			/* SET TABLESPACE */
	AT_SetRelOptions,			/* SET (...) -- AM特定参数 */
	AT_ResetRelOptions,			/* RESET (...) -- AM特定参数 */
	AT_ReplaceRelOptions,		/* 完全替换reloption列表 */
	AT_EnableTrig,				/* 启用触发器名称 */
	AT_EnableAlwaysTrig,		/* 始终启用触发器名称 */
	AT_EnableReplicaTrig,		/* 启用副本触发器名称 */
	AT_DisableTrig,				/* 禁用触发器名称 */
	AT_EnableTrigAll,			/* 启用所有触发器 */
	AT_DisableTrigAll,			/* 禁用所有触发器 */
	AT_EnableTrigUser,			/* 启用用户触发器 */
	AT_DisableTrigUser,			/* 禁用用户触发器 */
	AT_EnableRule,				/* 启用规则名称 */
	AT_EnableAlwaysRule,		/* 始终启用规则名称 */
	AT_EnableReplicaRule,		/* 启用副本规则名称 */
	AT_DisableRule,				/* 禁用规则名称 */
	AT_AddInherit,				/* 继承父级 */
	AT_DropInherit,				/* 不继承父级 */
	AT_AddOf,					/* OF <type_name> */
	AT_DropOf,					/* NOT OF */
	AT_ReplicaIdentity,			/* REPLICA IDENTITY */
	AT_EnableRowSecurity,		/* 启用行安全性 */
	AT_DisableRowSecurity,		/* 禁用行安全性 */
	AT_ForceRowSecurity,		/* 强制行安全性 */
	AT_NoForceRowSecurity,		/* 不强制行安全性 */
	AT_GenericOptions,			/* OPTIONS (...) */
	AT_AttachPartition,			/* 附加分区 */
	AT_DetachPartition,			/* 脱离分区 */
	AT_DetachPartitionFinalize, /* 脱离分区最终化 */
	AT_AddIdentity,				/* 添加标识 */
	AT_SetIdentity,				/* 设置标识列选项 */
	AT_DropIdentity,			/* 删除标识 */
	AT_ReAddStatistics			/* 命令/tablecmds.c内部 */
} AlterTableType;

typedef struct ReplicaIdentityStmt
{
	NodeTag		type;
	char		identity_type;
	char	   *name;
} ReplicaIdentityStmt;

typedef struct AlterTableCmd	/* ALTER TABLE 的一个子命令 */
{
	NodeTag		type;
	AlterTableType subtype;		/* 应用的表更改类型 */
	char	   *name;			/* 要操作的列、约束或触发器，或表空间 */
	int16		num;			/* 由数字引用的列的属性编号 */
	RoleSpec   *newowner;
	Node	   *def;			/* 新列、索引、约束或父表的定义 */
	DropBehavior behavior;		/* 删除情况的限制或级联 */
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
	bool		recurse;		/* 执行时递归 */
} AlterTableCmd;


/* ----------------------
 * 修改排序
 * ----------------------
 */
typedef struct AlterCollationStmt
{
	NodeTag		type;
	List	   *collname;
} AlterCollationStmt;


/* ----------------------
 * 修改域
 *
 * 这些字段在命令的不同变体中有不同的用途。
 * ----------------------
 */
typedef struct AlterDomainStmt
{
	NodeTag		type;
	char		subtype;		/*------------
								 *	T = 修改列默认值
								 *	N = 修改列删除非空
								 *	O = 修改列设置非空
								 *	C = 添加约束
								 *	X = 删除约束
								 *------------
								 */
	List	   *typeName;		/* 要操作的域 */
	char	   *name;			/* 要操作的列或约束名称 */
	Node	   *def;			/* 默认或约束的定义 */
	DropBehavior behavior;		/* 删除情况的限制或级联 */
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
} AlterDomainStmt;


/* ----------------------
 * 授予|撤销语句
 * ----------------------
 */
typedef enum GrantTargetType
{
	ACL_TARGET_OBJECT,			/* 在特定命名对象上授予 */
	ACL_TARGET_ALL_IN_SCHEMA,	/* 在给定模式中的所有对象上授予 */
	ACL_TARGET_DEFAULTS			/* 修改默认权限 */
} GrantTargetType;

typedef struct GrantStmt
{
	NodeTag		type;
	bool		is_grant;		/* true = 授予，false = 撤销 */
	GrantTargetType targtype;	/* 授予目标的类型 */
	ObjectType	objtype;		/* 被操作的对象类型 */
	List	   *objects;		/* RangeVar 节点、带参数的对象节点或普通名称的列表（作为字符串值） */
	List	   *privileges;		/* AccessPriv 节点的列表 */
	/* privileges == NIL 表示 ALL PRIVILEGES */
	List	   *grantees;		/* RoleSpec 节点列表 */
	bool		grant_option;	/* 授予或撤销授予选项 */
	RoleSpec   *grantor;
	DropBehavior behavior;		/* 撤销行为（对于 REVOKE） */
} GrantStmt;

/*
 * ObjectWithArgs 表示一个函数/过程/运算符名称加上参数
 * 标识。
 *
 * objargs 仅包括对象输入参数的类型。
 * 在某些上下文中，这可能是我们所拥有的全部信息，并且根据
 * 传统的 Postgres 规则查找对象是足够的（即，当仅输入
 * 参数重要时）。
 *
 * objfuncargs，如果不为 NIL，则携带包含参数模式注释的
 * 参数列表的完整规范。
 *
 * 一些语法产生可以将 args_unspecified 设置为 true，而不是
 * 提供参数信息。在这种情况下，仅当对象名称是唯一时，
 * 查找将成功。注意，其他情况下，NIL 参数列表意味着零个参数。
 */
typedef struct ObjectWithArgs
{
	NodeTag		type;
	List	   *objname;		/* 函数/运算符的合格名称 */
	List	   *objargs;		/* 类型名称节点列表（仅输入参数） */
	List	   *objfuncargs;	/* 函数参数节点列表 */
	bool		args_unspecified;	/* 参数列表是否被省略？ */
} ObjectWithArgs;

/*
 * 访问特权，带可选的列名称列表
 * priv_name == NULL 表示所有特权（仅与列列表一起使用）
 * cols == NIL 表示“所有列”
 * 注意，简单的“所有特权”表示为 NIL 列，而不是
 * 具有两个字段均为 null 的 AccessPriv。
 */
typedef struct AccessPriv
{
	NodeTag		type;
	char	   *priv_name;		/* 特权的字符串名称 */
	List	   *cols;			/* 字符串列表 */
} AccessPriv;

/* ----------------------
 *		授予/撤销角色语句
 *
 * 注意：由于 GRANT <privileges> 语句的解析模糊性，
 * granted_roles 是 AccessPriv 的列表；如果出现任何列列表，
 * 执行代码应该进行抱怨。grantee_roles 是角色名称列表，
 * 作为字符串值。
 * ----------------------
 */
typedef struct GrantRoleStmt
{
	NodeTag		type;
	List	   *granted_roles;	/* 要授予/撤销的角色列表 */
	List	   *grantee_roles;	/* 要添加/删除的成员角色列表 */
	bool		is_grant;		/* true = 授予，false = 撤销 */
	bool		admin_opt;		/* 带有管理员选项 */
	RoleSpec   *grantor;		/* 将授予者设置为当前角色以外的角色 */
	DropBehavior behavior;		/* 撤销行为（对于 REVOKE） */
} GrantRoleStmt;

/* ----------------------
 *	更改默认特权语句
 * ----------------------
 */
typedef struct AlterDefaultPrivilegesStmt
{
	NodeTag		type;
	List	   *options;		/* DefElem 列表 */
	GrantStmt  *action;			/* GRANT/REVOKE 操作（带对象=NIL） */
} AlterDefaultPrivilegesStmt;

/* ----------------------
 *		复制语句
 *
 * 我们支持 “COPY relation FROM file”, “COPY relation TO file”, 和
 * “COPY (query) TO file”。在任何给定的 CopyStmt 中，
 * “relation”和“query”必须恰好有一个非 NULL。
 * ----------------------
 */
typedef struct CopyStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要复制的关系 */
	Node	   *query;			/* 要复制的查询（SELECT 或 DML 语句
								 * RETURNING），作为原始解析树 */
	List	   *attlist;		/* 列名称列表（作为字符串），或 NIL
								 * 表示所有列 */
	bool		is_from;		/* TO 或 FROM */
	bool		is_program;		/* 'filename' 是一个程序以 popen 吗？ */
	char	   *filename;		/* 文件名，或 NULL 表示 STDIN/STDOUT */
	List	   *options;		/* DefElem 节点列表 */
	Node	   *whereClause;	/* WHERE 条件（或 NULL） */
} CopyStmt;

/* ----------------------
 * SET 语句（包括 RESET）
 *
 * “SET var TO DEFAULT”和“RESET var”在语义上是等效的，
 * 但我们在 VariableSetKind 中保留 CreateCommandTag() 的 Distinction。
 * ----------------------
 */
typedef enum VariableSetKind
{
	VAR_SET_VALUE,				/* SET var = value */
	VAR_SET_DEFAULT,			/* SET var TO DEFAULT */
	VAR_SET_CURRENT,			/* 从 CURRENT 设置变量 */
	VAR_SET_MULTI,				/* 特殊情况用于设置事务... */
	VAR_RESET,					/* 重置变量 */
	VAR_RESET_ALL				/* 重置所有 */
} VariableSetKind;

typedef struct VariableSetStmt
{
	NodeTag		type;
	VariableSetKind kind;
	char	   *name;			/* 要设置的变量 */
	List	   *args;			/* A_Const 节点列表 */
	bool		is_local;		/* 设置 LOCAL? */
} VariableSetStmt;

/* ----------------------
 * 显示语句
 * ----------------------
 */
typedef struct VariableShowStmt
{
	NodeTag		type;
	char	   *name;
} VariableShowStmt;

/* ----------------------
 *		创建表语句
 *
 * 注意：在原始的 gram.y 输出中，ColumnDef 和 Constraint 节点是
 * 混合在 tableElts 中，constraints 是 NIL。在解析分析后，
 * tableElts 仅包含 ColumnDefs，constraints 仅包含
 * Constraint 节点（实际上，在当前实现中，只有 CONSTR_CHECK 节点）。
 * ----------------------
 */

typedef struct CreateStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 要创建的关系 */
	List	   *tableElts;		/* 列定义（ColumnDef 列表） */
	List	   *inhRelations;	/* 要继承的关系（RangeVar 列表） */
	PartitionBoundSpec *partbound;	/* FOR VALUES 子句 */
	PartitionSpec *partspec;	/* PARTITION BY 子句 */
	TypeName   *ofTypename;		/* 类型名称的 OF */
	List	   *constraints;	/* 约束（Constraint 节点列表） */
	List	   *options;		/* 来自 WITH 子句的选项 */
	OnCommitAction oncommit;	/* 在 COMMIT 时我们要做什么？ */
	char	   *tablespacename; /* 要使用的表空间，或 NULL */
	char	   *accessMethod;	/* 表访问方法 */
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
} CreateStmt;

/* ----------
 * CreateStmt 中约束的定义
 *
 * 请注意，列默认值被视为一种约束类型，
 * 即使这在语义上有点奇怪。
 *
 * 对于使用表达式的约束（CONSTR_CHECK，CONSTR_DEFAULT），
 * 我们可以在“原始”形式（未转换的解析树）或“熟成”形式
 * （可执行表达式树的 nodeToString 表示）中获得表达式，
 * 具体取决于该 Constraint 节点是如何创建的（通过解析，
 * 或通过继承现有关系）。我们永远不应该在同一个节点中
 * 同时存在两者！
 *
 * FKCONSTR_ACTION_xxx 值存储在 pg_constraint.confupdtype
 * 和 pg_constraint.confdeltype 列中；FKCONSTR_MATCH_xxx 值
 * 存储在 pg_constraint.confmatchtype 中。更改代码值可能
 * 需要初始化数据库（initdb）！
 *
 * 如果 skip_validation 为 true，则跳过检查表中现有行
 * 是否满足约束，仅安装约束的目录条目。新的 FK 约束
 * 仅在 initially_valid 为 true 时标记为有效。（通常，skip_validation
 * 和 initially_valid 是相反的，但如果表已知为空，则可以同时
 * 设置为 true。）
 *
 * 约束属性（DEFERRABLE 等）最初被表示为
 * 单独的 Constraint 节点，以简化解析。parse_utilcmd.c 对约束
 * 列表进行一次处理，以将信息插入适当的 Constraint 节点。
 * ----------
 */

typedef enum ConstrType			/* 约束的类型 */
{
	CONSTR_NULL,				/* 不是标准 SQL，但很多人
 * 期望它 */
	CONSTR_NOTNULL,
	CONSTR_DEFAULT,
	CONSTR_IDENTITY,
	CONSTR_GENERATED,
	CONSTR_CHECK,
	CONSTR_PRIMARY,
	CONSTR_UNIQUE,
	CONSTR_EXCLUSION,
	CONSTR_FOREIGN,
	CONSTR_ATTR_DEFERRABLE,		/* 以前约束节点的属性 */
	CONSTR_ATTR_NOT_DEFERRABLE,
	CONSTR_ATTR_DEFERRED,
	CONSTR_ATTR_IMMEDIATE
} ConstrType;

/* 外键操作码 */
#define FKCONSTR_ACTION_NOACTION	'a'
#define FKCONSTR_ACTION_RESTRICT	'r'
#define FKCONSTR_ACTION_CASCADE		'c'
#define FKCONSTR_ACTION_SETNULL		'n'
#define FKCONSTR_ACTION_SETDEFAULT	'd'

/* 外键匹配类型代码 */
#define FKCONSTR_MATCH_FULL			'f'
#define FKCONSTR_MATCH_PARTIAL		'p'
#define FKCONSTR_MATCH_SIMPLE		's'

typedef struct Constraint
{
	NodeTag		type;
	ConstrType	contype;		/* 详见上文 */

	/* 用于大多数/所有约束类型的字段： */
	char	   *conname;		/* 约束名称，或 NULL 如果没有命名 */
	bool		deferrable;		/* 是否可推迟？ */
	bool		initdeferred;	/* 初始推迟？ */
	int			location;		/* 令牌位置，如果未知则为-1 */

	/* 用于带有表达式的约束（CHECK 和 DEFAULT）的字段： */
	bool		is_no_inherit;	/* 约束是否不可继承？ */
	Node	   *raw_expr;		/* expr, as untransformed parse tree */
	char	   *cooked_expr;	/* expr, as nodeToString representation */
	char		generated_when; /* ALWAYS or BY DEFAULT */

	/* 用于唯一约束（UNIQUE 和 PRIMARY KEY）的字段： */
	bool		nulls_not_distinct; /* UNIQUE 约束的 null 处理 */
	List	   *keys;			/* 命名引用键列的字符串节点 */
	List	   *including;		/* 命名引用非键列的字符串节点 */

	/* 用于排除约束的字段： */
	List	   *exclusions;		/* (IndexElem, operator name) 对的列表 */

	/* 用于索引约束（UNIQUE，PRIMARY KEY，EXCLUSION）的字段： */
	List	   *options;		/* 来自 WITH 子句的选项 */
	char	   *indexname;		/* 要使用的现有索引；否则为 NULL */
	char	   *indexspace;		/* 索引表空间；默认为 NULL */
	bool		reset_default_tblspc;	/* 在创建索引之前重置 default_tablespace */
	/* 这些可能被用于 UNIQUE/PKEY，但当前并没有： */
	char	   *access_method;	/* 索引访问方法；默认为 NULL */
	Node	   *where_clause;	/* 部分索引谓词 */

	/* 用于外键约束的字段： */
	RangeVar   *pktable;		/* 主键表 */
	List	   *fk_attrs;		/* 外键的属性 */
	List	   *pk_attrs;		/* 在 PK 表中的对应属性 */
	char		fk_matchtype;	/* FULL，PARTIAL，SIMPLE */
	char		fk_upd_action;	/* ON UPDATE 操作 */
	char		fk_del_action;	/* ON DELETE 操作 */
	List	   *fk_del_set_cols;	/* ON DELETE SET NULL/DEFAULT (col1, col2) */
	List	   *old_conpfeqop;	/* pg_constraint.conpfeqop 的前身 */
	Oid			old_pktable_oid;	/* pg_constraint.confrelid 的前身 */

	/* 用于允许 NOT VALID 规范的约束的字段 */
	bool		skip_validation;	/* 跳过现有行的验证？ */
	bool		initially_valid;	/* 将新约束标记为有效？ */
} Constraint;

/* ----------------------
 *		Create/Drop Table Space Statements
 * ----------------------
 */  

typedef struct CreateTableSpaceStmt
{
	NodeTag		type;
	char	   *tablespacename;
	RoleSpec   *owner;
	char	   *location;
	List	   *options;
} CreateTableSpaceStmt;

typedef struct DropTableSpaceStmt
{
	NodeTag		type;
	char	   *tablespacename;
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
} DropTableSpaceStmt;

typedef struct AlterTableSpaceOptionsStmt
{
	NodeTag		type;
	char	   *tablespacename;
	List	   *options;
	bool		isReset;
} AlterTableSpaceOptionsStmt;

typedef struct AlterTableMoveAllStmt
{
	NodeTag		type;
	char	   *orig_tablespacename;
	ObjectType	objtype;		/* 对象类型移动 */
	List	   *roles;			/* 移动对象的角色列表 */
	char	   *new_tablespacename;
	bool		nowait;
} AlterTableMoveAllStmt;

/* ----------------------
 *		创建/修改扩展语句
 * ----------------------
 */

typedef struct CreateExtensionStmt
{
	NodeTag		type;
	char	   *extname;
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
	List	   *options;		/* DefElem 节点列表 */
} CreateExtensionStmt;

/* 仅用于 ALTER EXTENSION UPDATE；后面可能需要一个操作字段 */
typedef struct AlterExtensionStmt
{
	NodeTag		type;
	char	   *extname;
	List	   *options;		/* DefElem 节点列表 */
} AlterExtensionStmt;

typedef struct AlterExtensionContentsStmt
{
	NodeTag		type;
	char	   *extname;		/* 扩展的名称 */
	int			action;			/* +1 = 添加对象，-1 = 删除对象 */
	ObjectType	objtype;		/* 对象的类型 */
	Node	   *object;			/* 对象的合格名称 */
} AlterExtensionContentsStmt;

/* ----------------------
 *		创建/修改 FOREIGN DATA WRAPPER 语句
 * ----------------------
 */

typedef struct CreateFdwStmt
{
	NodeTag		type;
	char	   *fdwname;		/* 外部数据包装器名称 */
	List	   *func_options;	/* HANDLER/VALIDATOR 选项 */
	List	   *options;		/* FDW 的通用选项 */
} CreateFdwStmt;

typedef struct AlterFdwStmt
{
	NodeTag		type;
	char	   *fdwname;		/* 外部数据包装器名称 */
	List	   *func_options;	/* HANDLER/VALIDATOR 选项 */
	List	   *options;		/* FDW 的通用选项 */
} AlterFdwStmt;

/* ----------------------
 *		创建/修改 FOREIGN SERVER 语句
 * ----------------------
 */

typedef struct CreateForeignServerStmt
{
	NodeTag		type;
	char	   *servername;		/* 服务器名称 */
	char	   *servertype;		/* 可选的服务器类型 */
	char	   *version;		/* 可选的服务器版本 */
	char	   *fdwname;		/* FDW name */
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
	List	   *options;		/* 服务器的通用选项 */
} CreateForeignServerStmt;

typedef struct AlterForeignServerStmt
{
	NodeTag		type;
	char	   *servername;		/* 服务器名称 */
	char	   *version;		/* 可选的服务器版本 */
	List	   *options;		/* 服务器的通用选项 */
	bool		has_version;	/* 指定的版本 */
} AlterForeignServerStmt;

/* ----------------------
 *		创建 FOREIGN TABLE 语句
 * ----------------------
 */

typedef struct CreateForeignTableStmt
{
	CreateStmt	base;
	char	   *servername;
	List	   *options;
} CreateForeignTableStmt;

/* ----------------------
 *		创建/删除 USER MAPPING 语句
 * ----------------------
 */

typedef struct CreateUserMappingStmt
{
	NodeTag		type;
	RoleSpec   *user;			/* 用户角色 */
	char	   *servername;		/* 服务器名称 */
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
	List	   *options;		/* 服务器的通用选项 */
} CreateUserMappingStmt;

typedef struct AlterUserMappingStmt
{
	NodeTag		type;
	RoleSpec   *user;			/* 用户角色 */
	char	   *servername;		/* 服务器名称 */
	List	   *options;		/* 服务器的通用选项 */
} AlterUserMappingStmt;

typedef struct DropUserMappingStmt
{
	NodeTag		type;
	RoleSpec   *user;			/* 用户角色 */
	char	   *servername;		/* 服务器名称 */
	bool		missing_ok;		/* 忽略缺失的映射 */
} DropUserMappingStmt;

/* ----------------------
 *		导入外部模式语句
 * ----------------------
 */

typedef enum ImportForeignSchemaType
{
	FDW_IMPORT_SCHEMA_ALL,		/* 所有想要的关系 */
	FDW_IMPORT_SCHEMA_LIMIT_TO, /* 在导入中仅包含列出的表 */
	FDW_IMPORT_SCHEMA_EXCEPT	/* 从导入中排除列出的表 */
} ImportForeignSchemaType;

typedef struct ImportForeignSchemaStmt
{
	NodeTag		type;
	char	   *server_name;	/* FDW 服务器名称 */
	char	   *remote_schema;	/* 要查询的远程模式名称 */
	char	   *local_schema;	/* 创建对象的本地模式 */
	ImportForeignSchemaType list_type;	/* 表列表类型 */
	List	   *table_list;		/* RangeVar 列表 */
	List	   *options;		/* list of options to pass to FDW */
} ImportForeignSchemaStmt;

/*----------------------
 *		创建 POLICY 语句
 *----------------------
 */
typedef struct CreatePolicyStmt
{
	NodeTag		type;
	char	   *policy_name;	/* 策略名称 */
	RangeVar   *table;			/* 策略适用的表名称 */
	char	   *cmd_name;		/* 策略适用的命令名称 */
	bool		permissive;		/* 限制性或宽松策略 */
	List	   *roles;			/* 与策略相关联的角色 */
	Node	   *qual;			/* 策略的条件 */
	Node	   *with_check;		/* 策略的 WITH CHECK 条件。 */
} CreatePolicyStmt;

/*----------------------
 *		修改 POLICY 语句
 *----------------------
 */
typedef struct AlterPolicyStmt
{
	NodeTag		type;
	char	   *policy_name;	/* 策略名称 */
	RangeVar   *table;			/* 策略适用的表名称 */
	List	   *roles;			/* 与策略相关联的角色 */
	Node	   *qual;			/* 策略的条件 */
	Node	   *with_check;		/* 策略的 WITH CHECK 条件。 */
} AlterPolicyStmt;

/*----------------------
 *		创建 ACCESS METHOD 语句
 *----------------------
 */
typedef struct CreateAmStmt
{
	NodeTag		type;
	char	   *amname;			/* 访问方法名称 */
	List	   *handler_name;	/* 处理函数名称 */
	char		amtype;			/* 访问方法类型 */
} CreateAmStmt;

/* ----------------------
 *		创建 TRIGGER 语句
 * ----------------------
 */
typedef struct CreateTrigStmt
{
	NodeTag		type;
	bool		replace;		/* 如果已存在则替换触发器 */
	bool		isconstraint;	/* 这是一个约束触发器 */
	char	   *trigname;		/* TRIGGER 名称 */
	RangeVar   *relation;		/* 触发器所在的关系 */
	List	   *funcname;		/* 要调用的函数的合格名称 */
	List	   *args;			/* 字符串列表或 NIL */
	bool		row;			/* ROW/STATEMENT */
	/* 时机使用 catalog/pg_trigger.h 中定义的 TRIGGER_TYPE 位 */
	int16		timing;			/* BEFORE, AFTER, 或 INSTEAD */
	/* 事件使用 catalog/pg_trigger.h 中定义的 TRIGGER_TYPE 位 */
	int16		events;			/* INSERT/UPDATE/DELETE/TRUNCATE 的 "OR" */
	List	   *columns;		/* 列名称，或 NIL 表示所有列 */
	Node	   *whenClause;		/* 合格表达式，或 NULL 如果没有 */
	/* 明确命名的转换数据 */
	List	   *transitionRels; /* TriggerTransition 节点，或 NIL 如果没有 */
	/* 剩余字段仅用于约束触发器 */
	bool		deferrable;		/* [NOT] DEFERRABLE */
	bool		initdeferred;	/* 最初 {延迟|立即} */
	RangeVar   *constrrel;		/* 反向关系，如果RI触发 */
} CreateTrigStmt;

/* ----------------------
 *		创建事件触发器语句
 * ----------------------
 */
typedef struct CreateEventTrigStmt
{
	NodeTag		type;
	char	   *trigname;		/* TRIGGER 名称 */
	char	   *eventname;		/* 事件的标识符 */
	List	   *whenclause;		/* 表示过滤的DefElems列表 */
	List	   *funcname;		/* 要调用的函数的合格名称 */
} CreateEventTrigStmt;

/* ----------------------
 *		修改事件触发器语句
 * ----------------------
 */
typedef struct AlterEventTrigStmt
{
	NodeTag		type;
	char	   *trigname;		/* TRIGGER 名称 */
	char		tgenabled;		/* 关于 session_replication_role 的触发器触发配置 */
} AlterEventTrigStmt;

/* ----------------------
 *		创建语言语句
 * ----------------------
 */
typedef struct CreatePLangStmt
{
	NodeTag		type;
	bool		replace;		/* T => 如果已经存在则替换 */
	char	   *plname;			/* PL name */
	List	   *plhandler;		/* PL调用处理程序函数（限定名称） */
	List	   *plinline;		/* 可选内联函数（限定名称） */
	List	   *plvalidator;	/* 可选验证函数（限定名称） */
	bool		pltrusted;		/* PL是可信的 */
} CreatePLangStmt;

/* ----------------------
 *		创建/修改/删除角色语句
 *
 * 注意：这些节点类型也用于向后兼容的
 * 创建/修改/删除用户/组语句。在ALTER和DROP情况下
 * 实际上不需要区分原始拼写是什么，
 * 但对于CREATE我们标记类型因为默认值不同。
 * ----------------------
 */
typedef enum RoleStmtType
{
	ROLESTMT_ROLE,
	ROLESTMT_USER,
	ROLESTMT_GROUP
} RoleStmtType;

typedef struct CreateRoleStmt
{
	NodeTag		type;
	RoleStmtType stmt_type;		/* 角色/用户/组 */
	char	   *role;			/* 角色名称 */
	List	   *options;		/* DefElem 节点列表 */
} CreateRoleStmt;

typedef struct AlterRoleStmt
{
	NodeTag		type;
	RoleSpec   *role;			/* role */
	List	   *options;		/* DefElem 节点列表 */
	int			action;			/* +1 = 添加成员, -1 = 删除成员 */
} AlterRoleStmt;

typedef struct AlterRoleSetStmt
{
	NodeTag		type;
	RoleSpec   *role;			/* role */
	char	   *database;		/* 数据库名称，或NULL */
	VariableSetStmt *setstmt;	/* SET或RESET子命令 */
} AlterRoleSetStmt;

typedef struct DropRoleStmt
{
	NodeTag		type;
	List	   *roles;			/* 要移除的角色列表 */
	bool		missing_ok;		/* 如果缺少角色是否跳过错误？ */
} DropRoleStmt;

/* ----------------------
 *		{创建|修改}序列语句
 * ----------------------
 */

typedef struct CreateSeqStmt
{
	NodeTag		type;
	RangeVar   *sequence;		/* 要创建的序列 */
	List	   *options;
	Oid			ownerId;		/* 拥有者的ID，或InvalidOid作为默认值 */
	bool		for_identity;
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
} CreateSeqStmt;

typedef struct AlterSeqStmt
{
	NodeTag		type;
	RangeVar   *sequence;		/* 要修改的序列 */
	List	   *options;
	bool		for_identity;
	bool		missing_ok;		/* 如果缺少角色是否跳过错误？ */
} AlterSeqStmt;

/* ----------------------
 *		创建{聚合|操作符|类型}语句
 * ----------------------
 */
typedef struct DefineStmt
{
	NodeTag		type;
	ObjectType	kind;			/* 聚合，操作符，类型 */
	bool		oldstyle;		/* 黑客信号旧的CREATE AGG语法 */
	List	   *defnames;		/* 限定名称（字符串列表） */
	List	   *args;			/* 类型名称列表（如有需要） */
	List	   *definition;		/* DefElem列表 */
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
	bool		replace;		/* 如果已存在，则替换？ */
} DefineStmt;

/* ----------------------
 *		创建域语句
 * ----------------------
 */
typedef struct CreateDomainStmt
{
	NodeTag		type;
	List	   *domainname;		/* 限定名称（字符串列表） */
	TypeName   *typeName;		/* 基础类型 */
	CollateClause *collClause;	/* 未转化的 COLLATE 规范（如果有的话） */
	List	   *constraints;	/* 约束（Constraint 节点列表） */
} CreateDomainStmt;

/* ----------------------
 *		创建操作符类语句
 * ----------------------
 */
typedef struct CreateOpClassStmt
{
	NodeTag		type;
	List	   *opclassname;	/* 限定名称（字符串列表） */
	List	   *opfamilyname;	/* 合格名称（同上）；如果省略则为NIL */
	char	   *amname;			/* 索引AM操作类的名称 */
	TypeName   *datatype;		/* 被索引列的数据类型 */
	List	   *items;			/* CreateOpClassItem节点列表 */
	bool		isDefault;		/* 是否应标记为该类型的默认值？ */
} CreateOpClassStmt;

#define OPCLASS_ITEM_OPERATOR		1
#define OPCLASS_ITEM_FUNCTION		2
#define OPCLASS_ITEM_STORAGETYPE	3

typedef struct CreateOpClassItem
{
	NodeTag		type;
	int			itemtype;		/* 参见上面的代码 */
	ObjectWithArgs *name;		/* 操作符或函数名称和参数 */
	int			number;			/* 策略编号或支持过程编号 */
	List	   *order_family;	/* 仅用于排序操作符 */
	List	   *class_args;		/* amproclefttype/amprocrighttype或
								 * amoplefttype/amoprighttype */
	/* 用于存储类型项的字段： */
	TypeName   *storedtype;		/* 存储在索引中的数据类型 */
} CreateOpClassItem;

/* ----------------------
 *		创建操作符族语句
 * ----------------------
 */
typedef struct CreateOpFamilyStmt
{
	NodeTag		type;
	List	   *opfamilyname;	/* 限定名称（字符串列表） */
	char	   *amname;			/* 索引AM操作族的名称 */
} CreateOpFamilyStmt;

/* ----------------------
 *		修改操作符族语句
 * ----------------------
 */
typedef struct AlterOpFamilyStmt
{
	NodeTag		type;
	List	   *opfamilyname;	/* 限定名称（字符串列表） */
	char	   *amname;			/* 索引AM操作族的名称 */
	bool		isDrop;			/* 添加还是删除这些项？ */
	List	   *items;			/* CreateOpClassItem节点列表 */
} AlterOpFamilyStmt;

/* ----------------------
 *		删除表|序列|视图|索引|类型|域|转换|模式语句
 * ----------------------
 */

typedef struct DropStmt
{
	NodeTag		type;
	List	   *objects;		/* 名称列表 */
	ObjectType	removeType;		/* 对象类型 */
	DropBehavior behavior;		/* RESTRICT或CASCADE行为 */
	bool		missing_ok;		/* 如果对象缺失是否跳过错误？ */
	bool		concurrent;		/* 是否并发删除索引？ */
} DropStmt;

/* ----------------------
 *				截断表语句
 * ----------------------
 */
typedef struct TruncateStmt
{
	NodeTag		type;
	List	   *relations;		/* 要被截断的关系（RangeVars） */
	bool		restart_seqs;	/* 重新启动拥有的序列？ */
	DropBehavior behavior;		/* RESTRICT或CASCADE行为 */
} TruncateStmt;

/* ----------------------
 *				评论语句
 * ----------------------
 */
typedef struct CommentStmt
{
	NodeTag		type;
	ObjectType	objtype;		/* 对象的类型 */
	Node	   *object;			/* 对象的合格名称 */
	char	   *comment;		/* 要插入的评论，或NULL以移除 */
} CommentStmt;

/* ----------------------
 *				安全标签语句
 * ----------------------
 */
typedef struct SecLabelStmt
{
	NodeTag		type;
	ObjectType	objtype;		/* 对象的类型 */
	Node	   *object;			/* 对象的合格名称 */
	char	   *provider;		/* 标签提供者（或NULL） */
	char	   *label;			/* 新安全标签将被分配 */
} SecLabelStmt;

/* ----------------------
 *		声明游标语句
 *
 * “query”字段最初是一个原始解析树，并在解析分析期间转换为
 * 查询节点。请注意，查询的重写和规划总是推迟到执行时。
 * ----------------------
 */
#define CURSOR_OPT_BINARY		0x0001	/* BINARY */
#define CURSOR_OPT_SCROLL		0x0002	/* 显式给定 SCROLL */
#define CURSOR_OPT_NO_SCROLL	0x0004	/* 显式给定 NO SCROLL */
#define CURSOR_OPT_INSENSITIVE	0x0008	/* 不敏感 */
#define CURSOR_OPT_ASENSITIVE	0x0010	/* ASENSITIVE */
#define CURSOR_OPT_HOLD			0x0020	/* WITH HOLD */
/* 这些规划器控制标志与任何 SQL 语法不对应： */
#define CURSOR_OPT_FAST_PLAN	0x0100	/* 偏好快速启动计划 */
#define CURSOR_OPT_GENERIC_PLAN 0x0200	/* 强制使用通用计划 */
#define CURSOR_OPT_CUSTOM_PLAN	0x0400	/* 强制使用自定义计划 */
#define CURSOR_OPT_PARALLEL_OK	0x0800	/* 并行模式可用 */

typedef struct DeclareCursorStmt
{
	NodeTag		type;
	char	   *portalname;		/* 门户（游标）的名称 */
	int			options;		/* 选项的位掩码（见上文） */
	Node	   *query;			/* 查询（见上文评论） */
} DeclareCursorStmt;

/* ----------------------
 *		关闭门户语句
 * ----------------------
 */
typedef struct ClosePortalStmt
{
	NodeTag		type;
	char	   *portalname;		/* 门户（游标）的名称 */
	/* NULL 表示 CLOSE ALL */
} ClosePortalStmt;

/* ----------------------
 *		获取语句（也可移动）
 * ----------------------
 */
typedef enum FetchDirection
{
	/* 对于这些，howMany 是要获取的行数；FETCH_ALL 表示所有 */
	FETCH_FORWARD,
	FETCH_BACKWARD,
	/* 对于这些，howMany 表示一个位置；只获取一行 */
	FETCH_ABSOLUTE,
	FETCH_RELATIVE
} FetchDirection;

#define FETCH_ALL	LONG_MAX

typedef struct FetchStmt
{
	NodeTag		type;
	FetchDirection direction;	/* 详见上文 */
	long		howMany;		/* 行数或位置参数 */
	char	   *portalname;		/* 门户（游标）的名称 */
	bool		ismove;			/* 如果是移动，则为真 */
} FetchStmt;

/* ----------------------
 *		创建索引语句
 *
 * 这表示创建一个索引和/或相关约束。
 * 如果 isconstraint 为真，我们应该在创建索引的同时创建一个 pg_constraint 条目。
 * 但是如果 indexOid 不是 InvalidOid，我们并不是在创建索引，只是使用现有索引创建 UNIQUE/PKEY 约束。
 * 在这种情况下，isconstraint 必须始终为真，并且描述索引属性的字段为空。
 * ----------------------
 */
typedef struct IndexStmt
{
	NodeTag		type;
	char	   *idxname;		/* 新索引的名称，或 NULL 表示默认 */
	RangeVar   *relation;		/* 关系以构建索引 */
	char	   *accessMethod;	/* 访问方法的名称（例如 btree） */
	char	   *tableSpace;		/* 表空间，或 NULL 表示默认 */
	List	   *indexParams;	/* 要索引的列：IndexElem 的列表 */
	List	   *indexIncludingParams;	/* 要索引的附加列：一个
										 * IndexElem 的列表 */
	List	   *options;		/* WITH 子句选项： DefElem 的列表 */
	Node	   *whereClause;	/* 限制条件（部分索引谓词） */
	List	   *excludeOpNames; /* 排除操作符名称，如果没有则为 NIL */
	char	   *idxcomment;		/* 应用于索引的注释，或 NULL */
	Oid			indexOid;		/* 已存在索引的 OID（对象标识符），如果有的话 */
	Oid			oldNode;		/* 已存在存储的 relfilenode，如果有的话 */
	SubTransactionId oldCreateSubid;	/* oldNode 的 rd_createSubid */
	SubTransactionId oldFirstRelfilenodeSubid;	/* oldNode 的 rd_firstRelfilenodeSubid */
	bool		unique;			/* 索引是否唯一？ */
	bool		nulls_not_distinct; /* UNIQUE 约束的 null 处理 */
	bool		primary;		/* 索引是否为主键？ */
	bool		isconstraint;	/* 是否为主键/唯一约束？ */
	bool		deferrable;		/* 约束是否可延迟？ */
	bool		initdeferred;	/* 约束是否初始为延迟？ */
	bool		transformed;	/* 当 transformIndexStmt 完成时为真 */
	bool		concurrent;		/* 这应该是一个并发索引构建吗？ */
	bool		if_not_exists;	/* 如果索引已存在则什么都不做？ */
	bool		reset_default_tblspc;	/* 在执行前重置 default_tablespace */
} IndexStmt;

/* ----------------------
 *		创建统计信息语句
 * ----------------------
 */
typedef struct CreateStatsStmt
{
	NodeTag		type;
	List	   *defnames;		/* 限定名称（字符串列表） */
	List	   *stat_types;		/* 统计类型（字符串列表） */
	List	   *exprs;			/* 用于构建统计信息的表达式 */
	List	   *relations;		/* 构建统计信息的关系（RangeVar 列表） */
	char	   *stxcomment;		/* 应用于统计信息的注释，或 NULL */
	bool		transformed;	/* 当 transformStatsStmt 完成时为真 */
	bool		if_not_exists;	/* 如果统计名称已存在则什么都不做 */
} CreateStatsStmt;

/*
 * StatsElem - 统计参数（用于创建统计信息）
 *
 * 对于一个普通属性，'name' 是引用的表列的名称，
 * 而 'expr' 是 NULL。对于一个表达式，'name' 是 NULL，
 * 而 'expr' 是表达式树。
 */
typedef struct StatsElem
{
	NodeTag		type;
	char	   *name;			/* 要索引的属性名称，或 NULL */
	Node	   *expr;			/* 要索引的表达式，或 NULL */
} StatsElem;


/* ----------------------
 *		修改统计信息语句
 * ----------------------
 */
typedef struct AlterStatsStmt
{
	NodeTag		type;
	List	   *defnames;		/* 限定名称（字符串列表） */
	int			stxstattarget;	/* 统计目标 */  
	bool		missing_ok;		/* 如果统计对象缺失则跳过错误 */
} AlterStatsStmt;

/* ----------------------
 *		创建函数语句
 * ----------------------
 */
typedef struct CreateFunctionStmt
{
	NodeTag		type;
	bool		is_procedure;	/* 实际上是创建存储过程 */
	bool		replace;		/* T => 如果已经存在则替换 */
	List	   *funcname;		/* 要创建的函数的限定名称 */
	List	   *parameters;		/* 一个 FunctionParameter 列表 */
	TypeName   *returnType;		/* 返回类型 */
	List	   *options;		/* DefElem列表 */
	Node	   *sql_body;
} CreateFunctionStmt;

typedef enum FunctionParameterMode
{
	/* 分配的枚举值出现在pg_proc中，请不要更改它们！ */
	FUNC_PARAM_IN = 'i',		/* 仅输入 */
	FUNC_PARAM_OUT = 'o',		/* 仅输出 */
	FUNC_PARAM_INOUT = 'b',		/* both */
	FUNC_PARAM_VARIADIC = 'v',	/* 可变参数（始终为输入） */
	FUNC_PARAM_TABLE = 't',		/* 表函数输出列 */
	/* 这在pg_proc中未使用： */
	FUNC_PARAM_DEFAULT = 'd'	/* 默认；有效地与IN相同 */
} FunctionParameterMode;

typedef struct FunctionParameter
{
	NodeTag		type;
	char	   *name;			/* 参数名称，或者如果未给出则为NULL */
	TypeName   *argType;		/* 参数类型的TypeName */
	FunctionParameterMode mode; /* IN/OUT/等 */
	Node	   *defexpr;		/* 原始默认表达式，如果未给出则为NULL */
} FunctionParameter;

typedef struct AlterFunctionStmt
{
	NodeTag		type;
	ObjectType	objtype;
	ObjectWithArgs *func;		/* 函数的名称和参数 */
	List	   *actions;		/* DefElem 列表 */
} AlterFunctionStmt;

/* ----------------------
 *		执行声明
 *
 * DoStmt是原始解析器输出，InlineCodeBlock是执行时的API
 * ----------------------
 */
typedef struct DoStmt
{
	NodeTag		type;
	List	   *args;			/* DefElem 节点列表 */
} DoStmt;

typedef struct InlineCodeBlock
{
	NodeTag		type;
	char	   *source_text;	/* 匿名代码块的源文本 */
	Oid			langOid;		/* 选择语言的OID */
	bool		langIsTrusted;	/* 语言的可信属性 */
	bool		atomic;			/* 原子执行上下文 */
} InlineCodeBlock;

/* ----------------------
 *		CALL 声明
 *
 * OUT模式参数从变换的funcexpr中移除。outargs
 * 列表包含所有输出参数的表达式副本，以程序声明的参数顺序。因此，outargs
 * 从未被计算，但对调用者作为分配时的参考很有用。
 * ----------------------
 */
typedef struct CallStmt
{
	NodeTag		type;
	FuncCall   *funccall;		/* 来自解析器 */
	FuncExpr   *funcexpr;		/* 变换后的调用，仅包含输入参数 */
	List	   *outargs;		/* 变换后的输出参数表达式 */
} CallStmt;

typedef struct CallContext
{
	NodeTag		type;
	bool		atomic;
} CallContext;

/* ----------------------
 *		修改对象重命名声明
 * ----------------------
 */
typedef struct RenameStmt
{
	NodeTag		type;
	ObjectType	renameType;		/* OBJECT_TABLE, OBJECT_COLUMN 等 */
	ObjectType	relationType;	/* 如果是列名，相关关系类型 */
	RangeVar   *relation;		/* 如果是一个表 */
	Node	   *object;			/* 如果是其他对象 */
	char	   *subname;		/* 包含对象的名称（列，规则，
								 * 触发器等） */
	char	   *newname;		/* 新名称 */
	DropBehavior behavior;		/* RESTRICT或CASCADE行为 */
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
} RenameStmt;

/* ----------------------
 * ALTER 对象依赖于扩展 extname
 * ----------------------
 */
typedef struct AlterObjectDependsStmt
{
	NodeTag		type;
	ObjectType	objectType;		/* OBJECT_FUNCTION, OBJECT_TRIGGER 等 */
	RangeVar   *relation;		/* 如果涉及到表 */
	Node	   *object;			/* 对象的名称 */
	String	   *extname;		/* 扩展名称 */
	bool		remove;			/* 设置为 true 以移除依赖，而不是添加 */
} AlterObjectDependsStmt;

/* ----------------------
 *		ALTER 对象设置架构语句
 * ----------------------
 */
typedef struct AlterObjectSchemaStmt
{
	NodeTag		type;
	ObjectType	objectType;		/* OBJECT_TABLE, OBJECT_TYPE 等 */
	RangeVar   *relation;		/* 如果是一个表 */
	Node	   *object;			/* 如果是其他对象 */
	char	   *newschema;		/* 新架构 */
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
} AlterObjectSchemaStmt;

/* ----------------------
 *		更改对象所有者语句
 * ----------------------
 */
typedef struct AlterOwnerStmt
{
	NodeTag		type;
	ObjectType	objectType;		/* OBJECT_TABLE, OBJECT_TYPE 等 */
	RangeVar   *relation;		/* 如果是一个表 */
	Node	   *object;			/* 如果是其他对象 */
	RoleSpec   *newowner;		/* 新所有者 */
} AlterOwnerStmt;

/* ----------------------
 *		更改操作符集（this-n-that）
 * ----------------------
 */
typedef struct AlterOperatorStmt
{
	NodeTag		type;
	ObjectWithArgs *opername;	/* 操作符名称和参数类型 */
	List	   *options;		/* DefElem 节点列表 */
} AlterOperatorStmt;

/* ------------------------
 *		更改类型集（this-n-that）
 * ------------------------
 */
typedef struct AlterTypeStmt
{
	NodeTag		type;
	List	   *typeName;		/* 类型名称（可能带有限定） */
	List	   *options;		/* DefElem 节点列表 */
} AlterTypeStmt;

/* ----------------------
 *		创建规则语句
 * ----------------------
 */
typedef struct RuleStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 规则涉及的关系 */
	char	   *rulename;		/* 规则名称 */
	Node	   *whereClause;	/* 限定条件 */
	CmdType		event;			/* SELECT, INSERT 等 */
	bool		instead;		/* 是 '代替执行' 吗？ */
	List	   *actions;		/* 动作语句 */
	bool		replace;		/* 或替换 */
} RuleStmt;

/* ----------------------
 *		通知语句
 * ----------------------
 */
typedef struct NotifyStmt
{
	NodeTag		type;
	char	   *conditionname;	/* 要通知的条件名称 */
	char	   *payload;		/* 负载字符串，或为 NULL 如果没有 */
} NotifyStmt;

/* ----------------------
 *		监听语句
 * ----------------------
 */
typedef struct ListenStmt
{
	NodeTag		type;
	char	   *conditionname;	/* 要监听的条件名称 */
} ListenStmt;

/* ----------------------
 *		取消监听语句
 * ----------------------
 */
typedef struct UnlistenStmt
{
	NodeTag		type;
	char	   *conditionname;	/* 要取消监听的名称，或为 NULL 表示全部 */
} UnlistenStmt;

/* ----------------------
 *		{开始|提交|回滚}事务语句
 * ----------------------
 */
typedef enum TransactionStmtKind
{
	TRANS_STMT_BEGIN,
	TRANS_STMT_START,			/* 在语义上与 BEGIN 相同 */
	TRANS_STMT_COMMIT,
	TRANS_STMT_ROLLBACK,
	TRANS_STMT_SAVEPOINT,
	TRANS_STMT_RELEASE,
	TRANS_STMT_ROLLBACK_TO,
	TRANS_STMT_PREPARE,
	TRANS_STMT_COMMIT_PREPARED,
	TRANS_STMT_ROLLBACK_PREPARED
} TransactionStmtKind;

typedef struct TransactionStmt
{
	NodeTag		type;
	TransactionStmtKind kind;	/* 详见上文 */
	List	   *options;		/* 用于 BEGIN/START 命令 */
	char	   *savepoint_name; /* 保存点命令 */
	char	   *gid;			/* 与双阶段提交相关的命令 */
	bool		chain;			/* AND CHAIN 选项 */
} TransactionStmt;

/* ----------------------
 *		创建类型语句，复合类型
 * ----------------------
 */
typedef struct CompositeTypeStmt
{
	NodeTag		type;
	RangeVar   *typevar;		/* 要创建的复合类型 */
	List	   *coldeflist;		/* ColumnDef 节点列表 */
} CompositeTypeStmt;

/* ----------------------
 *		创建类型语句，枚举类型
 * ----------------------
 */
typedef struct CreateEnumStmt
{
	NodeTag		type;
	List	   *typeName;		/* 限定名称（字符串列表） */
	List	   *vals;			/* 枚举值（字符串列表） */
} CreateEnumStmt;

/* ----------------------
 *		创建类型语句，范围类型
 * ----------------------
 */
typedef struct CreateRangeStmt
{
	NodeTag		type;
	List	   *typeName;		/* 限定名称（字符串列表） */
	List	   *params;			/* 范围参数（DefElem 列表） */
} CreateRangeStmt;

/* ----------------------
 *		修改类型语句，枚举类型
 * ----------------------
 */
typedef struct AlterEnumStmt
{
	NodeTag		type;
	List	   *typeName;		/* 限定名称（字符串列表） */
	char	   *oldVal;			/* 旧枚举值的名称，如果重命名 */
	char	   *newVal;			/* 新枚举值的名称 */
	char	   *newValNeighbor; /* 邻近的枚举值，如果指定 */
	bool		newValIsAfter;	/* 新枚举值放在邻近值后面吗？ */
	bool		skipIfNewValExists; /* 如果新值已存在则不报错？ */
} AlterEnumStmt;

/* ----------------------
 *		创建视图语句
 * ----------------------
 */
typedef enum ViewCheckOption
{
	NO_CHECK_OPTION,
	LOCAL_CHECK_OPTION,
	CASCADED_CHECK_OPTION
} ViewCheckOption;

typedef struct ViewStmt
{
	NodeTag		type;
	RangeVar   *view;			/* 要创建的视图 */
	List	   *aliases;		/* 目标列名 */
	Node	   *query;			/* SELECT 查询（作为原始解析树） */
	bool		replace;		/* 替换现有视图吗？ */
	List	   *options;		/* 来自 WITH 子句的选项 */
	ViewCheckOption withCheckOption;	/* WITH CHECK OPTION */
} ViewStmt;

/* ----------------------
 *		加载语句
 * ----------------------
 */
typedef struct LoadStmt
{
	NodeTag		type;
	char	   *filename;		/* 要加载的文件 */
} LoadStmt;

/* ----------------------
 *		创建数据库语句
 * ----------------------
 */
typedef struct CreatedbStmt
{
	NodeTag		type;
	char	   *dbname;			/* 要创建的数据库名称 */
	List	   *options;		/* DefElem 节点列表 */
} CreatedbStmt;

/* ----------------------
 *		修改数据库
 * ----------------------
 */
typedef struct AlterDatabaseStmt
{
	NodeTag		type;
	char	   *dbname;			/* 要修改的数据库名称 */
	List	   *options;		/* DefElem 节点列表 */
} AlterDatabaseStmt;

typedef struct AlterDatabaseRefreshCollStmt
{
	NodeTag		type;
	char	   *dbname;
} AlterDatabaseRefreshCollStmt;

typedef struct AlterDatabaseSetStmt
{
	NodeTag		type;
	char	   *dbname;			/* 数据库名称 */
	VariableSetStmt *setstmt;	/* SET或RESET子命令 */
} AlterDatabaseSetStmt;

/* ----------------------
 *		删除数据库语句
 * ----------------------
 */
typedef struct DropdbStmt
{
	NodeTag		type;
	char	   *dbname;			/* 要删除的数据库 */
	bool		missing_ok;		/* 如果数据库缺失是否跳过错误？ */
	List	   *options;		/* 当前仅支持 FORCE */
} DropdbStmt;

/* ----------------------
 *		修改系统语句
 * ----------------------
 */
typedef struct AlterSystemStmt
{
	NodeTag		type;
	VariableSetStmt *setstmt;	/* SET 子命令 */
} AlterSystemStmt;

/* ----------------------
 *		集群语句（支持 pbrown 的集群索引实现）
 * ----------------------
 */
typedef struct ClusterStmt
{
	NodeTag		type;
	RangeVar   *relation;		/* 索引的关系，如果全部则为 NULL */
	char	   *indexname;		/* 原始索引定义 */
	List	   *params;			/* DefElem 节点列表 */
} ClusterStmt;

/* ----------------------
 *		清理和分析语句
 *
 * 尽管这名义上是两个语句，但使用
 * 一个节点类型来处理两者是方便的。
 * ----------------------
 */
typedef struct VacuumStmt
{
	NodeTag		type;
	List	   *options;		/* DefElem 节点列表 */
	List	   *rels;			/* VacuumRelation 列表，或者所有则为 NIL */
	bool		is_vacuumcmd;	/* VACUUM 为 true，ANALYZE 为 false */
} VacuumStmt;

/*
 * 关于 VACUUM/ANALYZE 单个目标表的信息。
 *
 * 如果 OID 字段被设置，它总是标识要处理的表。
 * 然后关系字段可以为 NULL；如果不是，它仅用于报告
 * 打开/锁定关系失败。
 */
typedef struct VacuumRelation
{
	NodeTag		type;
	RangeVar   *relation;		/* 要处理的表名，或 NULL */
	Oid			oid;			/* 表的 OID；如果未查找则为 InvalidOid */
	List	   *va_cols;		/* 列名称列表，或 NIL 表示所有 */
} VacuumRelation;

/* ----------------------
 *		解释语句
 *
 * “查询”字段最初是一个原始解析树，并在解析分析期间转换为
 * 查询节点。请注意，查询的重写和规划
 * 总是推迟到执行时。
 * ----------------------
 */
typedef struct ExplainStmt
{
	NodeTag		type;
	Node	   *query;			/* 查询（见上文评论） */
	List	   *options;		/* DefElem 节点列表 */
} ExplainStmt;

/* ----------------------
 *		创建表 as 语句（也称为 SELECT INTO）
 *
 * 以 CREATE TABLE AS 书写的查询将原生产生这种节点类型。
 * 以 SELECT ... INTO 书写的查询将在解析分析期间转换为这种形式。
 * 以 CREATE MATERIALIZED view 书写的查询将在解析分析期间生成这种节点类型，
 * 因为它需要所有相同的数据。
 *
 * “查询”字段的处理方式类似于 EXPLAIN，尽管注意它
 * 可以是 SELECT 或 EXECUTE，但不能是其他 DML 语句。
 * ----------------------
 */
typedef struct CreateTableAsStmt
{
	NodeTag		type;
	Node	   *query;			/* 查询（见上文评论） */
	IntoClause *into;			/* 目标表 */
	ObjectType	objtype;		/* OBJECT_TABLE 或 OBJECT_MATVIEW */
	bool		is_select_into; /* 以 SELECT INTO 书写 */
	bool		if_not_exists;	/* 如果已存在就什么都不做？ */
} CreateTableAsStmt;

/* ----------------------
 *		刷新物化视图语句
 * ----------------------
 */
typedef struct RefreshMatViewStmt
{
	NodeTag		type;
	bool		concurrent;		/* 是否允许并发访问？ */
	bool		skipData;		/* 对于 WITH NO DATA 为 true */
	RangeVar   *relation;		/* 要插入的关系 */
} RefreshMatViewStmt;

/* ----------------------
 * 检查点语句
 * ----------------------
 */
typedef struct CheckPointStmt
{
	NodeTag		type;
} CheckPointStmt;

/* ----------------------
 * 丢弃语句
 * ----------------------
 */

typedef enum DiscardMode
{
	DISCARD_ALL,
	DISCARD_PLANS,
	DISCARD_SEQUENCES,
	DISCARD_TEMP
} DiscardMode;

typedef struct DiscardStmt
{
	NodeTag		type;
	DiscardMode target;
} DiscardStmt;

/* ----------------------
 *		锁定语句
 * ----------------------
 */
typedef struct LockStmt
{
	NodeTag		type;
	List	   *relations;		/* 要锁定的关系 */
	int			mode;			/* 锁定模式 */
	bool		nowait;			/* 不等待模式 */
} LockStmt;

/* ----------------------
 *		设置约束语句
 * ----------------------
 */
typedef struct ConstraintsSetStmt
{
	NodeTag		type;
	List	   *constraints;	/* 作为 RangeVars 的名称列表 */
	bool		deferred;
} ConstraintsSetStmt;

/* ----------------------
 *		重建索引语句
 * ----------------------
 */
typedef enum ReindexObjectType
{
	REINDEX_OBJECT_INDEX,		/* index */
	REINDEX_OBJECT_TABLE,		/* 表或物化视图 */
	REINDEX_OBJECT_SCHEMA,		/* schema */
	REINDEX_OBJECT_SYSTEM,		/* 系统目录 */
	REINDEX_OBJECT_DATABASE		/* database */
} ReindexObjectType;

typedef struct ReindexStmt
{
	NodeTag		type;
	ReindexObjectType kind;		/* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE,
								 * 等等。 */
	RangeVar   *relation;		/* 要重建索引的表或索引 */
	const char *name;			/* 数据库名称以重新索引 */
	List	   *params;			/* DefElem 节点列表 */
} ReindexStmt;

/* ----------------------
 *		CREATE CONVERSION 语句
 * ----------------------
 */
typedef struct CreateConversionStmt
{
	NodeTag		type;
	List	   *conversion_name;	/* 转换的名称 */
	char	   *for_encoding_name;	/* 源编码名称 */
	char	   *to_encoding_name;	/* 目标编码名称 */
	List	   *func_name;		/* 合格的转换函数名称 */
	bool		def;			/* 这是默认转换吗？ */
} CreateConversionStmt;

/* ----------------------
 *	CREATE CAST 语句
 * ----------------------
 */
typedef struct CreateCastStmt
{
	NodeTag		type;
	TypeName   *sourcetype;
	TypeName   *targettype;
	ObjectWithArgs *func;
	CoercionContext context;
	bool		inout;
} CreateCastStmt;

/* ----------------------
 *	CREATE TRANSFORM 语句
 * ----------------------
 */
typedef struct CreateTransformStmt
{
	NodeTag		type;
	bool		replace;
	TypeName   *type_name;
	char	   *lang;
	ObjectWithArgs *fromsql;
	ObjectWithArgs *tosql;
} CreateTransformStmt;

/* ----------------------
 *		PREPARE 语句
 * ----------------------
 */
typedef struct PrepareStmt
{
	NodeTag		type;
	char	   *name;			/* 计划名称，任意 */
	List	   *argtypes;		/* 参数类型（类型名称列表） */
	Node	   *query;			/* 查询本身（作为原始解析树） */
} PrepareStmt;


/* ----------------------
 *		EXECUTE 语句
 * ----------------------
 */

typedef struct ExecuteStmt
{
	NodeTag		type;
	char	   *name;			/* 要执行的计划名称 */
	List	   *params;			/* 要分配给参数的值 */
} ExecuteStmt;


/* ----------------------
 *		DEALLOCATE 语句
 * ----------------------
 */
typedef struct DeallocateStmt
{
	NodeTag		type;
	char	   *name;			/* 要删除的计划名称 */
	/* NULL 表示 DEALLOCATE ALL */
} DeallocateStmt;

/*
 *		DROP OWNED 语句
 */
typedef struct DropOwnedStmt
{
	NodeTag		type;
	List	   *roles;
	DropBehavior behavior;
} DropOwnedStmt;

/*
 *		REASSIGN OWNED 语句
 */
typedef struct ReassignOwnedStmt
{
	NodeTag		type;
	List	   *roles;
	RoleSpec   *newrole;
} ReassignOwnedStmt;

/*
 * TS 字典语句： DefineStmt，RenameStmt 和 DropStmt 是默认的
 */
typedef struct AlterTSDictionaryStmt
{
	NodeTag		type;
	List	   *dictname;		/* 限定名称（字符串列表） */
	List	   *options;		/* DefElem 节点列表 */
} AlterTSDictionaryStmt;

/*
 * TS 配置语句： DefineStmt，RenameStmt 和 DropStmt 是默认的
 */
typedef enum AlterTSConfigType
{
	ALTER_TSCONFIG_ADD_MAPPING,
	ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN,
	ALTER_TSCONFIG_REPLACE_DICT,
	ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN,
	ALTER_TSCONFIG_DROP_MAPPING
} AlterTSConfigType;

typedef struct AlterTSConfigurationStmt
{
	NodeTag		type;
	AlterTSConfigType kind;		/* ALTER_TSCONFIG_ADD_MAPPING 等 */
	List	   *cfgname;		/* 限定名称（字符串列表） */

	/*
	 * 如果指定了 ADD/ALTER MAPPING，dicts 将为非 NIL。如果 dicts 为
	 * NIL，但 tokentype 不是，则指定了 DROP MAPPING。
	 */
	List	   *tokentype;		/* 字符串列表 */
	List	   *dicts;			/* 字符串列表的列表 */
	bool		override;		/* 如果为真 - 删除旧的变体 */
	bool		replace;		/* 如果为真 - 用另一个字典替换 */
	bool		missing_ok;		/* 对于 DROP - 如果缺失跳过错误？ */
} AlterTSConfigurationStmt;

typedef struct PublicationTable
{
	NodeTag		type;
	RangeVar   *relation;		/* 要发布的关系 */
	Node	   *whereClause;	/* 限定条件 */
	List	   *columns;		/* 发布表中的列列表 */
} PublicationTable;

/*
 * 发布对象类型
 */
typedef enum PublicationObjSpecType
{
	PUBLICATIONOBJ_TABLE,		/* A table */
	PUBLICATIONOBJ_TABLES_IN_SCHEMA,	/* 架构中的所有表 */
	PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA,	/* search_path中第一个元素中的所有表 */
	PUBLICATIONOBJ_CONTINUATION /* 上一个类型的延续 */
} PublicationObjSpecType;

typedef struct PublicationObjSpec
{
	NodeTag		type;
	PublicationObjSpecType pubobjtype;	/* 此发布对象的类型 */
	char	   *name;
	PublicationTable *pubtable;
	int			location;		/* 令牌位置，如果未知则为-1 */
} PublicationObjSpec;

typedef struct CreatePublicationStmt
{
	NodeTag		type;
	char	   *pubname;		/* 发布名称 */
	List	   *options;		/* DefElem 节点列表 */
	List	   *pubobjects;		/* 可选的发布对象列表 */
	bool		for_all_tables; /* 数据库中所有表的特殊发布 */
} CreatePublicationStmt;

typedef enum AlterPublicationAction
{
	AP_AddObjects,				/* 将对象添加到发布中 */
	AP_DropObjects,				/* 从发布中移除对象 */
	AP_SetObjects				/* 设置对象列表 */
} AlterPublicationAction;

typedef struct AlterPublicationStmt
{
	NodeTag		type;
	char	   *pubname;		/* 发布名称 */

	/* 用于ALTER PUBLICATION ... WITH的参数 */
	List	   *options;		/* DefElem 节点列表 */

	/*
	 * 用于ALTER PUBLICATION ... ADD/DROP/SET发布对象的参数。
	 */
	List	   *pubobjects;		/* 可选的发布对象列表 */
	bool		for_all_tables; /* 数据库中所有表的特殊发布 */
	AlterPublicationAction action;	/* 对给定对象执行的操作 */
} AlterPublicationStmt;

typedef struct CreateSubscriptionStmt
{
	NodeTag		type;
	char	   *subname;		/* 订阅的名称 */
	char	   *conninfo;		/* 连接到发布者的连接字符串 */
	List	   *publication;	/* 一个或多个要订阅的发布 */
	List	   *options;		/* DefElem 节点列表 */
} CreateSubscriptionStmt;

typedef enum AlterSubscriptionType
{
	ALTER_SUBSCRIPTION_OPTIONS,
	ALTER_SUBSCRIPTION_CONNECTION,
	ALTER_SUBSCRIPTION_SET_PUBLICATION,
	ALTER_SUBSCRIPTION_ADD_PUBLICATION,
	ALTER_SUBSCRIPTION_DROP_PUBLICATION,
	ALTER_SUBSCRIPTION_REFRESH,
	ALTER_SUBSCRIPTION_ENABLED,
	ALTER_SUBSCRIPTION_SKIP
} AlterSubscriptionType;

typedef struct AlterSubscriptionStmt
{
	NodeTag		type;
	AlterSubscriptionType kind; /* ALTER_SUBSCRIPTION_OPTIONS等 */
	char	   *subname;		/* 订阅的名称 */
	char	   *conninfo;		/* 连接到发布者的连接字符串 */
	List	   *publication;	/* 一个或多个要订阅的发布 */
	List	   *options;		/* DefElem 节点列表 */
} AlterSubscriptionStmt;

typedef struct DropSubscriptionStmt
{
	NodeTag		type;
	char	   *subname;		/* 订阅的名称 */
	bool		missing_ok;		/* 如果缺失是否跳过错误？ */
	DropBehavior behavior;		/* RESTRICT或CASCADE行为 */
} DropSubscriptionStmt;

#endif							/* PARSENODES_H */
